Skip to content

feat(codec-registration-completion): unify codec registration (TML-2357)#417

Open
wmadden wants to merge 138 commits intomainfrom
tml-2357-codec-registration-model-complete-the-unified
Open

feat(codec-registration-completion): unify codec registration (TML-2357)#417
wmadden wants to merge 138 commits intomainfrom
tml-2357-codec-registration-model-complete-the-unified

Conversation

@wmadden
Copy link
Copy Markdown
Contributor

@wmadden wmadden commented May 1, 2026

Status: ready for review. All milestones complete; all 14 acceptance criteria PASS or LANDED at HEAD; validation gates green workspace-wide. Post-implementation surface cleanup (F9 + F10) and post-feedback hygiene round (F11–F39) landed on top.

Completes the registration-side migration that the parent codec-registry-unification project (merged via ADR 208) deliberately deferred. (TML-2357)

Spec & plan

Milestones

# Goal Spec ACs Status
M0 Class-based codec migration + per-codec helpers + Strength 3 deletion sweep AC-0, AC-1, AC-CB-1..6 SATISFIED at a210fa1c5
M1 Narrow runtime Codec instance + descriptor-keyed metadata reads AC-3 LANDED at 1be7564c4; reverified through M4
M2 Native descriptor migration + bridge / aliasCodec / arktypeJsonEmitCodec deletion AC-2, AC-4 ABSORBED into M0 (Phase B + Phase C)
M3 ParamRef.refs plumbing + encode-side forColumn + forCodecId retirement AC-5 SATISFIED at 3f0ec224a
M4 Delete JsonSchemaValidatorRegistry; retire 'json-validator' trait AC-6 SATISFIED at e055c9455
F9 + F10 Public-API surface cleanup: registry-only public surface; drop transition vocabulary hygiene SATISFIED at c4d81ad1c
F11–F39 Post-feedback hygiene round: 27 findings closed; F38 rejected; SQL CodecRegistry consolidated into CodecDescriptorRegistry hygiene + correctness SATISFIED at 0e3aafc0b
AC-7 Validation gates green AC-7 PASS at every milestone close + every hygiene-round close

What landed

  • Class-based codec hierarchy. interface CodecDescriptor<P> + abstract class CodecDescriptorImpl<P>, paired with interface Codec<Id, Traits, Wire, Input> + abstract class CodecImpl<...>. Per-codec column helpers (e.g. vectorColumn(N)) directly invoke descriptor.factory(params) to preserve method-level generics; satisfies ColumnHelperFor<D> ties helpers to their descriptor without polymorphism. AnyCodecDescriptor (alias for CodecDescriptor<any>) is the canonical heterogeneous-storage type.
  • Strength 3 forcing-function deletion. Every legacy carrier deleted: mkCodec, defineCodec, defineCodecGroup, defineCodecBundle, CodecDefBuilder*, synthesizeNonParameterizedDescriptor, instance-keyed ExtractCodecTypes, byScalar maps, dataTypes exports, sqlCodecDefinitions, codecDescriptorDefinitions, pgVectorRepresentativeCodec placeholder, parameterizedCodecs: slot, CodecParamsDescriptor, arktypeJsonEmitCodec, aliasCodec, aliasDescriptor function form, the 'json-validator' trait, JsonSchemaValidatorRegistry infrastructure, arktypeParamsSchema helper, the SQL-family CodecRegistry interface (consolidated into CodecDescriptorRegistry). Closing-grep zero call-sites.
  • ParamRef + ProjectionItem carry refs?: { table; column }; validateParamRefRefs builder-pipeline pass enforces refs for parameterized codec ids; encode/decode dispatch consults metadata.refs first via contractCodecs.forColumn(table, column).
  • JSON validation lives in the resolved codec's decode body (arktype-json's inline pattern from TML-2229). Decode-error envelope equivalence verified via codec-async.test.ts:408-456.
  • ColumnTypeDescriptor relocated from @prisma-next/contract-authoring (layer 2) to @prisma-next/framework-components (layer 1) so codec base types live with the framework primitives.
  • F8 portability fix (fae3bd688): CodecTypes exposed at the public exports/codec-types.ts entry point with a Resolve<T> materializer to break tsdown's chunk-private path reference and restore consumer-side typecheck.
  • F9 + F10 surface cleanup (3d57f9ecd..c4d81ad1c): each codec-shipping package now exposes only column helpers + a <package>CodecRegistry instance + type re-exports of descriptor types. Internal codecDescriptorMap / codecDescriptorClassList no longer surface through public exports. Transition vocabulary (Class suffixes, class-form / class-based in comments, codecs-class.ts filenames) scrubbed.

Post-feedback hygiene round (F11–F39)

19 commits between c4d81ad1c..0e3aafc0b close 27 findings surfaced from orchestrator-principal review and 30 GitHub PR review threads. Highlights:

  • F11 (f725db1f8) — rename ast/sql-codecs-class.tsast/sql-codecs.ts, split helpers into ast/sql-codec-helpers.ts.
  • F12 (7d56a39b4) — move parameterization predicate onto CodecDescriptorImpl.isParameterized getter; retire the standalone IsParameterizedCodecId callback type.
  • F13 + F14 + F20 (cfa078a23) — align arktype params schemas with TParams optionality ('length?': '...'); delete arktypeParamsSchema helper; consumer sites direct-assign with : StandardSchemaV1<TParams>. The arktype runtime dep stays in @prisma-next/contract because validate-contract.ts consumes it directly for structural validation — that's by design, not a follow-up.
  • F15 (1051f24e8) — replace unique symbol trait phantom with a string-key phantom property (__codecTraits) to avoid Node bundling failure modes.
  • F16 + F17 (083fff350, a278bd034) — rewrite codec-authoring-guide alias section + fix self-referential JSDoc helper-source reference.
  • F18 (7ee52fae0) — assert leaf scalar type in no-emit-typed-flow.test-d.ts to make AC-CB-6's literal claim explicit.
  • F19 + F31 + F32 + F33 (81c55248f, bc4e8d716) — harden extractCodecLookup: lift inline imports, tighten id to non-optional string, refine the silent catch so non-parameterized codecs throw immediately while parameterized factories that tolerate empty params still materialise representatives.
  • F21 (f1be14d55) — createStubAdapter returns a stable codec registry instance (no per-call rebuild).
  • F22 + F26 + F29 (20f99bffd) — dispatch correctness: refsFromLeft walks via collectColumnRefs to preserve refs for wrapping expressions; encode-side forColumn fall-through is structurally safe (F19 + ambiguousCodecIds rejection + byCodecId column-correct materialisation); pgvector length threaded into PgVectorCodec constructor with assertVector validating the dimension at every ingress.
  • F23 + F24 + F25 (48ed1d135) — type predicate isArktypeSchemaLike replaces blind cast in rehydrateSchema; @ts-expect-error replaces as any + biome-ignore in tests; toExtend replaces deprecated toMatchTypeOf matcher.
  • F27 (21b4cbca7, 0e3aafc0b) — retire SQL-family CodecRegistry.register() mutation surface in favour of buildCodecRegistry(descriptors) builder; phase-2 deletes the CodecRegistry interface entirely. Single registry surface in the SQL family is now CodecDescriptorRegistry.
  • F28 (9881a7efe) — buildCodecDescriptorRegistry throws on duplicate codecId.
  • F30 (7a3faf20f) — codecDescriptorMap relocated to core/codec-type-map.ts; Resolve<T> materialisation kept at the exports/ boundary per F8.
  • F34 + F35 + F36 (4178072fa) — postgres render hygiene: scale validation in pgNumericRenderOutputType; ISO 8601 regex for timestamps; string validation for enum values.
  • F37 (182d10c88) — SqliteDatetimeCodec rejects Invalid Date in decode/decodeJson.
  • F38rejected. Default identity codecs on CodecImpl would constrain its type signature and obscure where real conversion work happens. Convention stays: explicit identity overrides at codec-author site.
  • F39 (80ba4fd60) — enumParamsSchema and EnumParams tightened to readonly string[].

Closure-mechanism note for F22: the implementer chose a structural argument over fail-fast on forColumn miss — F19's refinement makes extractCodecLookup skip parameterized descriptors that don't tolerate empty params; buildContractCodecRegistry's ambiguousCodecIds set throws RUNTIME.TYPE_PARAMS_INVALID on multi-instance ids; for the non-ambiguous parameterized case byCodecId stores the column-correct per-instance codec. Reviewer cross-checked all three legs and accepted.

Notable side effect: 16 pre-existing e2e failures resolved by M3

Before M3, the e2e suite ran 75/91 with 16 failures of the form Codec '...' resolves to multiple parameterized instances; column-aware dispatch is required. — top-level field shortcuts (select('vectorCol')) emitted IdentifierRef AST that didn't carry (table, column) context, so decode-side resolveProjectionCodec fell back to forCodecId and threw. M3's ProjectionItem.refs extension + decode-side parity in decoding.ts closed the path. e2e is now 91/91.

Validation gates at HEAD 0e3aafc0b

Gate Result
pnpm typecheck PASS — 123/123
pnpm lint:deps PASS — 727 modules / 1444 deps / 0 violations
pnpm fixtures:check PASS — zero drift (demo emit byte-identical against origin/main)
pnpm build PASS — 62/62
pnpm test:e2e PASS — 91/91 (16 pre-existing failures resolved by M3)
pnpm test:packages PASS in scope (residual: pre-existing 7 sql-orm-client pgvector wire-format + TML-2402 parallel-flake)

Review artifacts

projects/codec-registration-completion/reviews/ carries three review artifacts produced by the reviewer subagent during orchestration. After user feedback that the initial structure didn't match the canonical skill output, all three were rewritten to conform to /drive-pr-local-review (flat F-numbered findings + AC verification table) and /drive-pr-walkthrough (intent-first semantic narrative). Final reviewer verdict at HEAD 0e3aafc0b: SATISFIED with 12 PASS / 2 WEAK on the AC scoreboard. The two WEAKs are AC-7 (acknowledged baseline test failures in sql-orm-client pgvector wire format + TML-2402 parallel flake) and AC-CB-5 (a single internal descriptor as unknown as AnyDescriptor cast inside buildCodecDescriptorRegistry — purely a registry-internal heterogeneous-storage erasure, not a public surface concern).

Linear follow-ups filed during close-out

  • TML-2402pnpm test:packages parallel-execution flake (adapter-postgres / cli / sql-orm-client; passes cleanly in isolation). P3.
  • TML-2403 — Turbo cache-keying gap on transitive AST/type-system changes (worked around with pnpm build --force). P4.
  • TML-2405 — Codec dispatch follow-up: reference codec instances on the lowered Plan instead of carrying (table, column) lookup keys on the AST. The current shape's validator pass is a smell; instance-on-Plan would retire forColumn/forCodecId from the runtime dispatch surface entirely. Architectural successor to this work. P3.

Out of scope

  • Mongo codec registration migration — folded into TML-2324 (Mongo runtime forColumn plumbing).
  • Renaming Codec — type name stays; only the field set narrows.
  • Reshaping the async codec runtime (ADR 204) or CodecCallContext (ADR 207).
  • pgEnumCodec placeholder factory audit (already clean at HEAD; documented in ADR 208 § Future work).
  • Retiring CodecLookup.get(id) and ProjectionItem.refs / ParamRef.refs lookup-key carriers from the AST — TML-2405.

Note on project artifacts

Per the user's mid-flight directive at close-out, projects/codec-registration-completion/ is preserved in-tree (the standard transient-directory deletion was reverted at 5b0113a5a). The directory's review artifacts under reviews/ are gitignored and don't appear in the diff; they live in the working tree only as historical context.

Open in Web Open in Cursor 

Summary by CodeRabbit

  • New Features

    • Unified descriptor-driven codec system for extensions and targets; extension packs now contribute codec descriptors.
    • Class-based codec authoring pattern and per-codec column helpers.
    • Per-call execution context (AbortSignal + column metadata) available to codecs.
  • Documentation

    • New codec authoring reference and updated ADRs describing descriptor model and async runtime.
    • Expanded testing guide including Mongo in-memory setup and testing patterns.
  • Improvements

    • Safer parameter validation and output-type rendering for parameterized codecs.
    • SQL builder now propagates column provenance (refs) through expressions and params.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 1, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

This change rearchitects all codec authoring, registration, lookup, parameterization, column helpers, and downstream registry usage across every part of the framework, targets, adapters, and extensions to use a unified class-based descriptor and registry pattern. Old factory, registry, and parameterized codec split logic is completely supplanted. All tests, typegen, docs, contract logic, and downstream wiring are rewritten to match the new unified infrastructure.

Changes

Unified Codec Descriptor Registry Migration

Layer / File(s) Summary
Core descriptor, codec, and column spec types
framework-components/src/shared/codec-descriptor.ts, framework-components/src/shared/codec.ts, framework-components/src/shared/column-spec.ts, ...
Defines foundational codec descriptor interfaces and classes, base Codec interface and implementation, and column spec shapes with coercions and helper typings for use in descriptor-based codec systems.
Descriptor registry and framework/adapter integration
framework-components/src/control/control-stack.ts, src/shared/codec-types.ts, registry build/plumbing, framework core and adapter runtime wiring
Overhauls the framework’s codec registry construction to build lookup from codecDescriptors; updates control stack, wiring for registration/lookup, and adapter/runtime interactions to use the new descriptor-driven registry and metadata APIs.
Codec descriptor and column helper implementations
SQL, Mongo, Postgres, SQLite, and extension codec implementations and exports
Rewrites all core, target, and extension codecs to use the class-based codec descriptor/instance/column helper pattern, ditching prior registry and builder outputs in favor of descriptor-driven lists and explicit parameter schemas with output type renderers.
Runtime codec dispatch, AST refs propagation, and validation
Runtime encode/decode, SQL AST nodes, param/column ref propagation, validation logic
Updates runtime and AST layers to use unified descriptor-driven codec registries and per-column materializations; enhances ParamRef and ProjectionItem AST nodes to carry binding metadata; enforces refs validation for parameterized codecs; removes legacy JSON-schema validator plumbing and updates output render logic.
Documentation, authoring guides, and test updates
Docs, ADRs, authoring materials, type/runtime tests and integrations
Expands documentation and architecture decisions for unified codec descriptors; rewrites and adds tests for runtime codec behavior, registry integration, refs propagation, type inference, and parameterized codecs; introduces helpers for test codec construction.

Sequence Diagram(s)

sequenceDiagram
  participant Author
  participant CodecDescriptor
  participant Registry
  participant Runtime
  participant Consumer
  Author->>CodecDescriptor: implements CodecImpl, DescriptorImpl
  CodecDescriptor->>Registry: descriptor registration (array)
  Runtime->>Registry: lookup(by id, type, meta, render)
  Registry->>CodecDescriptor: .factory(params)
  Runtime->>Codec: encode/decode/render via registry
  Consumer->>Registry: typegen or metadata lookup
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

Possibly related PRs

  • prisma/prisma-next#402: The main PR implements the unified CodecDescriptor/descriptor-driven codec registry, descriptor factories, and emitter resolveFieldTypeParams changes that are the same core design and code-level modifications described in PR #402 (ADR 208), so they are directly related.
  • prisma/prisma-next#312: The main PR and retrieved PR are directly related: both implement the shift to descriptor-driven codec registration and codec-dispatched output-type rendering (adding/using renderOutputType and a codec lookup/descriptor registry), so the changes are related.
  • prisma/prisma-next#400: Main PR continues and expands the same codec call-context/AbortSignal work (ADR 207, CodecCallContext/SqlCodecCallContext, runtimeAborted/raceAgainstAbort and threaded ctx changes) introduced in PR #400 — related.

Suggested reviewers

  • SevInf
  • aqrln

Poem

In a warren of types and code,
Rabbits gathered the codecs owed.
No more bumpy registry roads—
Descriptors hop in neat abode.
Helpers line with pointed ears,
Fields and params trust their peers.
A carrot cheers, for change appears! 🥕🐇

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch tml-2357-codec-registration-model-complete-the-unified

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented May 1, 2026

Open in StackBlitz

@prisma-next/mongo-runtime

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-runtime@417

@prisma-next/family-mongo

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/family-mongo@417

@prisma-next/sql-runtime

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-runtime@417

@prisma-next/family-sql

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/family-sql@417

@prisma-next/extension-arktype-json

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/extension-arktype-json@417

@prisma-next/middleware-telemetry

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/middleware-telemetry@417

@prisma-next/mongo

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo@417

@prisma-next/extension-paradedb

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/extension-paradedb@417

@prisma-next/extension-pgvector

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/extension-pgvector@417

@prisma-next/postgres

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/postgres@417

@prisma-next/sql-orm-client

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-orm-client@417

@prisma-next/sqlite

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sqlite@417

@prisma-next/target-mongo

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/target-mongo@417

@prisma-next/adapter-mongo

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/adapter-mongo@417

@prisma-next/driver-mongo

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/driver-mongo@417

@prisma-next/contract

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/contract@417

@prisma-next/utils

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/utils@417

@prisma-next/config

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/config@417

@prisma-next/errors

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/errors@417

@prisma-next/framework-components

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/framework-components@417

@prisma-next/operations

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/operations@417

@prisma-next/ts-render

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/ts-render@417

@prisma-next/contract-authoring

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/contract-authoring@417

@prisma-next/ids

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/ids@417

@prisma-next/psl-parser

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/psl-parser@417

@prisma-next/psl-printer

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/psl-printer@417

@prisma-next/cli

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/cli@417

@prisma-next/emitter

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/emitter@417

@prisma-next/migration-tools

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/migration-tools@417

prisma-next

npm i https://pkg.pr.new/prisma/prisma-next@417

@prisma-next/vite-plugin-contract-emit

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/vite-plugin-contract-emit@417

@prisma-next/mongo-codec

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-codec@417

@prisma-next/mongo-contract

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-contract@417

@prisma-next/mongo-value

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-value@417

@prisma-next/mongo-contract-psl

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-contract-psl@417

@prisma-next/mongo-contract-ts

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-contract-ts@417

@prisma-next/mongo-emitter

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-emitter@417

@prisma-next/mongo-schema-ir

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-schema-ir@417

@prisma-next/mongo-query-ast

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-query-ast@417

@prisma-next/mongo-orm

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-orm@417

@prisma-next/mongo-query-builder

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-query-builder@417

@prisma-next/mongo-lowering

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-lowering@417

@prisma-next/mongo-wire

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/mongo-wire@417

@prisma-next/sql-contract

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-contract@417

@prisma-next/sql-errors

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-errors@417

@prisma-next/sql-operations

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-operations@417

@prisma-next/sql-schema-ir

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-schema-ir@417

@prisma-next/sql-contract-psl

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-contract-psl@417

@prisma-next/sql-contract-ts

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-contract-ts@417

@prisma-next/sql-contract-emitter

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-contract-emitter@417

@prisma-next/sql-lane-query-builder

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-lane-query-builder@417

@prisma-next/sql-relational-core

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-relational-core@417

@prisma-next/sql-builder

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/sql-builder@417

@prisma-next/target-postgres

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/target-postgres@417

@prisma-next/target-sqlite

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/target-sqlite@417

@prisma-next/adapter-postgres

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/adapter-postgres@417

@prisma-next/adapter-sqlite

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/adapter-sqlite@417

@prisma-next/driver-postgres

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/driver-postgres@417

@prisma-next/driver-sqlite

npm i https://pkg.pr.new/prisma/prisma-next/@prisma-next/driver-sqlite@417

commit: c99c1ba

@wmadden wmadden force-pushed the tml-2357-codec-registration-model-complete-the-unified branch from 5e0dee5 to 692178c Compare May 1, 2026 18:12
@wmadden wmadden marked this pull request as ready for review May 8, 2026 05:58
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/2-sql/5-runtime/src/sql-context.ts (1)

493-516: ⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Don't collapse non-parameterized column codecs to one instance per codecId.

CodecInstanceContext is per materialization site, but this cache makes contractCodecs.forColumn() hand back the same codec instance for every column sharing a non-parameterized id. The first column wins the captured ctx.name / usedAt, so any non-parameterized codec that derives state from column context will behave incorrectly.

🛠️ Safer materialization shape
         } else if (!isParameterized) {
-          let cached = byCodecId.get(column.codecId);
-          if (!cached) {
-            const ctx: SqlCodecInstanceContext = {
-              name: `<shared:${column.codecId}>`,
-              usedAt: [{ table: tableName, column: columnName }],
-            };
-            const voidFactory = descriptor.factory as unknown as (
-              params: undefined,
-            ) => (ctx: SqlCodecInstanceContext) => Codec;
-            cached = voidFactory(undefined)(ctx);
-            byCodecId.set(column.codecId, cached);
-          }
-          resolvedCodec = cached;
+          const ctx: SqlCodecInstanceContext = {
+            name: `<anon:${tableName}.${columnName}>`,
+            usedAt: [{ table: tableName, column: columnName }],
+          };
+          const voidFactory = descriptor.factory as unknown as (
+            params: undefined,
+          ) => (ctx: SqlCodecInstanceContext) => Codec;
+          resolvedCodec = voidFactory(undefined)(ctx);
+          byCodecId.set(column.codecId, byCodecId.get(column.codecId) ?? resolvedCodec);
         }

If you still want a codec-id fallback, keep that representative instance separate from the per-column instances rather than reusing the column-scoped object for every site.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/2-sql/5-runtime/src/sql-context.ts` around lines 493 - 516, The code
currently caches the concrete Codec instance in byCodecId (via
voidFactory(undefined)(ctx)), causing every non-parameterized column to share
the same instance and captured ctx; instead cache the parameterless factory
function and invoke it per-column so each materialization site gets its own
Codec with its own SqlCodecInstanceContext. Concretely: in the branch that
handles non-parameterized codecs (where descriptor.factory is cast to
voidFactory), store the function returned by voidFactory(undefined) in byCodecId
(not the result of calling it with ctx), then for each column call that cached
factory with a fresh SqlCodecInstanceContext to produce resolvedCodec; update
uses of cached/voidFactory/byCodecId/resolvedCodec accordingly so
contractCodecs.forColumn() returns per-column instances.
🧹 Nitpick comments (7)
examples/prisma-next-demo/test/no-emit-typed-flow.test-d.ts (1)

20-22: ⚡ Quick win

Use package-export imports in this example test

Line 20 and Line 21 import internals via relative paths. For examples/**/test/**, this should validate the public API surface by importing from package exports (@prisma-next/...) instead.

As per coding guidelines, “Cross-package and integration tests: Import from package exports (@prisma-next/...) to verify the public API.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@examples/prisma-next-demo/test/no-emit-typed-flow.test-d.ts` around lines 20
- 22, The test imports package internals via relative paths; update the imports
to use the package-export public API instead: replace the relative imports that
bring in the types/symbols "contract" and "sql" with their corresponding
exported package paths so the test validates the public surface (import the
"contract" type and the "sql" helper from the package exports for
prisma/prisma-no-emit rather than from ../prisma/contract and
../src/prisma-no-emit/context).
packages/2-sql/4-lanes/relational-core/test/utils.ts (1)

4-11: ⚡ Quick win

Avoid /exports/ barrel imports in this test utility.

Line 10 and Line 11 import through ../src/exports/*; switch these to direct module imports to keep dependency boundaries explicit.

As per coding guidelines: “Avoid barrel files for exports; use direct file imports instead” and “Import from shared plane packages using package name and export identifier … not /exports/ paths.”

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/2-sql/4-lanes/relational-core/test/utils.ts` around lines 4 - 11,
The test utility currently imports Adapter, Codec, CodecRegistry,
LoweredStatement, SelectAst and ExecutionContext from barrel paths
('../src/exports/*'); change these to import the same symbols directly from
their concrete modules (the specific source files that define Adapter, Codec,
CodecRegistry, LoweredStatement, SelectAst and ExecutionContext) so you avoid
`/exports/` barrel imports and keep dependency boundaries explicit; update the
import statements to reference the original modules that declare those types and
remove the barrel paths.
packages/3-targets/3-targets/postgres/src/core/codecs.ts (1)

55-72: 💤 Low value

Redundant undefined check for precision parameter.

The function parameter declares precision as readonly precision: number (required), but line 60 checks if (precision === undefined). This check is unreachable given the type signature.

If precision can actually be undefined at runtime (e.g., from untyped callers), consider changing the type to readonly precision?: number. Otherwise, remove the redundant check.

♻️ Suggested fix if precision is guaranteed
 export const pgNumericRenderOutputType = (typeParams: {
   readonly precision: number;
   readonly scale?: number;
 }): string | undefined => {
   const precision = typeParams.precision;
-  if (precision === undefined) return undefined;
   if (
     typeof precision !== 'number' ||
     !Number.isFinite(precision) ||
     !Number.isInteger(precision)
   ) {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/3-targets/3-targets/postgres/src/core/codecs.ts` around lines 55 -
72, The check for precision being undefined in pgNumericRenderOutputType is
unreachable because typeParams declares readonly precision: number; remove the
if (precision === undefined) return undefined; branch and any related
early-return logic; alternatively, if precision can be missing at runtime,
change the signature to readonly precision?: number and keep the check —
reference the function name pgNumericRenderOutputType and the property
typeParams.precision when making the change.
packages/2-sql/2-authoring/contract-psl/test/fixtures.ts (1)

160-164: ⚡ Quick win

Harden codec-id presence checks with Object.hasOwn.

Line 160 and Line 163 currently rely on plain index lookups, which can accidentally treat prototype keys (for example, "constructor") as valid codec ids.

Suggested patch
 export const postgresCodecLookup: CodecLookup = {
   get: (id: string) => {
-    if (!targetTypesByCodecId[id]) return undefined;
+    if (!Object.hasOwn(targetTypesByCodecId, id)) return undefined;
     return { id } as ReturnType<CodecLookup['get']>;
   },
-  targetTypesFor: (id: string) => targetTypesByCodecId[id],
+  targetTypesFor: (id: string) =>
+    Object.hasOwn(targetTypesByCodecId, id) ? targetTypesByCodecId[id] : undefined,
   metaFor: () => undefined,
   renderOutputTypeFor: () => undefined,
 };

As per coding guidelines "Always use Object.hasOwn() instead of hasOwnProperty() to check for own properties."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/2-sql/2-authoring/contract-psl/test/fixtures.ts` around lines 160 -
164, Replace plain property index checks on targetTypesByCodecId with
Object.hasOwn to avoid treating prototype keys as valid codec ids: in the
implementation returning ReturnType<CodecLookup['get']> change the existence
check from if (!targetTypesByCodecId[id]) to if
(!Object.hasOwn(targetTypesByCodecId, id)) and in the targetTypesFor method
ensure it only returns targetTypesByCodecId[id] when
Object.hasOwn(targetTypesByCodecId, id) (otherwise return undefined); leave
metaFor as-is.
packages/1-framework/1-core/framework-components/test/codec.types.test-d.ts (1)

249-249: 💤 Low value

Use toExtend instead of deprecated toMatchTypeOf.

Per coding guidelines, toMatchTypeOf() is deprecated in Vitest's expectTypeOf API. Use toExtend<T>() instead.

♻️ Proposed fix
-  expectTypeOf<typeof reg>().toMatchTypeOf<Map<string, AnyCodecDescriptor>>();
+  expectTypeOf<typeof reg>().toExtend<Map<string, AnyCodecDescriptor>>();
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/1-framework/1-core/framework-components/test/codec.types.test-d.ts`
at line 249, Replace the deprecated expectTypeOf(...).toMatchTypeOf usage with
the supported generic toExtend form: locate the assertion using reg
(expectTypeOf<typeof reg>().toMatchTypeOf<Map<string, AnyCodecDescriptor>>())
and change it to use toExtend with the same generic type (expectTypeOf<typeof
reg>().toExtend<Map<string, AnyCodecDescriptor>>()); ensure the generic
parameter remains Map<string, AnyCodecDescriptor> and the assertion target
remains typeof reg.
packages/1-framework/1-core/framework-components/src/shared/column-spec.ts (1)

34-55: ⚡ Quick win

Thread the TCodecId generic through ColumnSpec to preserve codec ID literals in helper return types.

ColumnTypeDescriptor is generic in TCodecId, but ColumnSpec and the column() function drop this parameter. Codec ID literals widen to string at the helper boundary, losing type precision that downstream code (e.g., contract-dsl.ts) already extracts via Descriptor['codecId']. Threading the generic would maintain literal fidelity through the helper surface and align with the field-state pattern used in contract authoring.

♻️ Suggested type-surface fix
-export interface ColumnSpec<R, P extends Record<string, unknown> | undefined>
-  extends ColumnTypeDescriptor {
+export interface ColumnSpec<
+  TCodecId extends string,
+  R,
+  P extends Record<string, unknown> | undefined,
+> extends ColumnTypeDescriptor<TCodecId> {
   readonly codecFactory: (ctx: CodecInstanceContext) => R;
   readonly typeParams: P;
 }

-export function column<R, P extends Record<string, unknown> | undefined>(
+export function column<
+  TCodecId extends string,
+  R,
+  P extends Record<string, unknown> | undefined,
+>(
   codecFactory: (ctx: CodecInstanceContext) => R,
-  codecId: string,
+  codecId: TCodecId,
   typeParams: P,
   nativeType: string,
-): ColumnSpec<R, P> {
+): ColumnSpec<TCodecId, R, P> {
   return {
     codecFactory,
     codecId,
     typeParams,
     nativeType,
   };
 }

 export type ColumnHelperFor<D extends CodecDescriptor<any>> = (
   ...args: any[]
-) => ColumnSpec<unknown, ColumnHelperParams<D>>;
+) => ColumnSpec<D['codecId'], unknown, ColumnHelperParams<D>>;

 export type ColumnHelperForStrict<D extends CodecDescriptor<any>> = (
   ...args: any[]
-) => ColumnSpec<ReturnType<ReturnType<D['factory']>>, ColumnHelperParams<D>>;
+) => ColumnSpec<
+  D['codecId'],
+  ReturnType<ReturnType<D['factory']>>,
+  ColumnHelperParams<D>
+>;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/1-framework/1-core/framework-components/src/shared/column-spec.ts`
around lines 34 - 55, ColumnSpec currently drops the TCodecId generic from
ColumnTypeDescriptor which widens codecId literals to string; update ColumnSpec
to be generic in TCodecId and extend ColumnTypeDescriptor<TCodecId> (e.g. change
the declaration to something like interface ColumnSpec<TCodecId extends string,
R, P extends Record<string, unknown> | undefined> extends
ColumnTypeDescriptor<TCodecId>), keep the existing codecFactory and typeParams
members but use the P and R generics, and then propagate the TCodecId generic
through the column() helper signature so helper return types preserve codec ID
literals.
packages/3-extensions/sql-orm-client/src/types.ts (1)

302-305: ⚡ Quick win

Use ifDefined() instead of inline conditional object spreads in param().

Line 302-Line 305 currently uses inline spread conditionals; this codepath should use the shared helper for consistency with repo conventions.

As per coding guidelines, "Use ifDefined() from @prisma-next/utils/defined for conditional object spreads instead of inline conditional spread patterns".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/3-extensions/sql-orm-client/src/types.ts` around lines 302 - 305,
The inline conditional spreads in param() should be replaced with the shared
helper ifDefined from `@prisma-next/utils/defined`: import ifDefined and pass
ParamRef.of(value, ifDefined({ codecId }, { refs })) (or a single ifDefined call
that combines the optional codecId and refs objects) instead of the current
...(codecId !== undefined ? { codecId } : {}), ...(refs !== undefined ? { refs }
: {}); update the param() return to use ifDefined and remove the inline
conditional spreads while keeping ParamRef.of and the same option shape.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/architecture` docs/adrs/ADR 184 - Codec-owned value serialization.md:
- Line 59: The paragraph claims "the defineCodec() factory provides these
defaults" but defineCodec() is retired; update the text that describes
encodeJson/decodeJson to either mark the defineCodec() statement as historical
("historically, defineCodec() provided these defaults") or reword it to the
current authoring surface (e.g., explain that the codec class/descriptor default
implementations make encodeJson/decodeJson identity for JSON-safe types and only
Date/binary codecs override them); do the same for the duplicate instance of
this sentence elsewhere so the ADR is internally consistent.

In `@docs/reference/codec-authoring-guide.md`:
- Around line 262-269: Update the docs' references that point to old filenames
so readers are directed to the new class-style implementations: change mentions
of the pre-migration files (e.g. "sql-codecs.ts" and "codecs.ts") to the
migrated filenames "sql-codecs-class.ts" and "codecs-class.ts" in the paragraphs
that describe the aliasCodec helper, CodecDescriptorImpl<P>, and the alias
factory pattern (around the aliasCodec/CodecDescriptorImpl example); ensure any
other occurrences (including the similar text at lines ~320-331) are updated
consistently so the guide links to the current implementations.

In `@examples/prisma-next-demo/test/no-emit-typed-flow.test-d.ts`:
- Around line 27-32: The test title claims the User.id is a string but current
assertions only check presence; update the test "field.id.uuidv4() produces a
string-typed id field on User" to actually assert the scalar type (or rename the
test to reflect presence-only checks). Specifically, in the test referencing
UserStorageFields and IdField (from (typeof
contract.models)['User']['storage']['fields']), add a type-level assertion that
IdField's column (or the appropriate scalar property on IdField) is string-typed
(e.g., assert IdField['column'] equals string) using expectTypeOf, or change the
test name to remove the "string-typed" claim.

In `@packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs-class.ts`:
- Around line 67-76: lengthParamsSchema currently requires length but
LengthParams marks it optional and the sqlCharColumn/sqlVarcharColumn helpers
default params to {} which produces descriptors that validateTypeParams later
rejects; either relax lengthParamsSchema to make length optional (change to
'length?') so bare char/varchar is supported, or make LengthParams require
length and stop defaulting params to {} in the helper functions (sqlCharColumn,
sqlVarcharColumn and the other affected helpers mentioned) so callers must
provide length; update validateTypeParams usage accordingly to match the chosen
contract.

In `@packages/2-sql/4-lanes/relational-core/test/utils.ts`:
- Around line 39-41: profile.codecs() currently returns a new empty registry
every call (via emptyCodecRegistry()), causing registered codecs to be lost
between calls; fix by creating a single stable registry instance (e.g., const
codecRegistry = emptyCodecRegistry()) and have profile.codecs() return that same
codecRegistry so registrations persist; update the utils.ts factory that defines
profile.codecs() to initialize the registry once (module-scope or closure) and
return it on each call, leaving emptyCodecRegistry() usage but only invoked
once.

In `@packages/2-sql/5-runtime/src/codecs/encoding.ts`:
- Around line 56-62: When metadata.refs is present the resolution must use the
column path only and must not fall back to id-based resolution; in the block
that checks contractCodecs.forColumn(metadata.refs.table, metadata.refs.column)
(symbols: metadata.refs, contractCodecs, forColumn), change the logic so that if
byColumn is falsy you stop resolution immediately (e.g. return undefined or
throw a clear error) instead of continuing to
contractCodecs.forCodecId(metadata.codecId) or registry.get(metadata.codecId);
this ensures a missing column lookup fails fast rather than downgrading to
codec-id dispatch.

In `@packages/3-extensions/arktype-json/src/core/arktype-json-codec-class.ts`:
- Around line 144-154: Replace the blind cast in rehydrateSchema by adding a
type predicate (e.g. isArktypeSchemaLike) and use it to assert the return of
ark.schema(jsonIr) is an ArktypeSchemaLike before returning; if the predicate
fails throw the same runtimeError (preserving ARKTYPE_JSON_CODEC_ID and jsonIr)
so invalid shapes are rejected instead of being force-cast; keep the existing
try/catch and error message behavior around ark.schema and runtimeError.

In `@packages/3-extensions/arktype-json/test/arktype-json-codec-class.test.ts`:
- Around line 75-79: The test uses an explicit any cast and a biome-ignore;
replace that with a TypeScript compile-time suppression: remove the "as any" and
the biome lint suppression, and instead place a single-line "@ts-expect-error —
intentionally passing non-callable to test runtime guard" immediately above the
arktypeJsonColumn(notASchema) call (leaving notASchema typed as an object), so
the runtime negative-path assertion remains but the test follows the repo rule
against any/biome ignores; target the arktypeJsonColumn call in
arktype-json-codec-class.test.ts when making this change.

In
`@packages/3-extensions/arktype-json/test/arktype-json-codec-class.types.test-d.ts`:
- Around line 140-142: The type-test assertion for variable col uses the
deprecated matcher toMatchTypeOf; update the expectTypeOf(col) call to use
toExtend with the same generic target type ColumnSpec<ArktypeJsonCodecClass<{
name: string; price: number }>, ArktypeJsonTypeParams> so the assertion reads
expectTypeOf(col).toExtend<...>(), keeping the same generics (ColumnSpec,
ArktypeJsonCodecClass, ArktypeJsonTypeParams) and not changing the tested
variable name col.

In `@packages/3-extensions/sql-orm-client/src/types.ts`:
- Around line 292-294: refsFromLeft currently only handles kind === 'column-ref'
which drops refs for other AnyExpression shapes (so result.buildAst() loses refs
and breaks codec dispatch); update refsFromLeft (and the comparison factory
usage that passes result.buildAst()) to preserve/collect refs for any expression
by returning refs found on the expression (e.g., expression.refs if present) or
by recursively extracting column-ref nodes from
BinaryExpr/Unary/Identifier/Literal wrappers so column refs are not lost (keep
the return type { table: string; column: string } | undefined or adjust to
return refs array if needed and update callers accordingly); also replace the
inline conditional spreads in param() that do ...(codecId !== undefined ? {
codecId } : {}) and ...(refs !== undefined ? { refs } : {}) with the ifDefined()
helper from '@prisma-next/utils/defined' (add the import) to follow the
repository guideline.

In `@packages/3-targets/3-targets/postgres/src/core/codecs-class.ts`:
- Around line 110-126: The TypeScript type LengthParams marks length as optional
but lengthParamsSchema requires it, causing runtime validation failures when
helpers (e.g., pgBitColumn) pass {} as params; update lengthParamsSchema to make
length optional (change the schema key to 'length?' with the same constraint) so
the runtime arktype matches the LengthParams type and existing callers that
default params = {} continue to validate correctly.

In `@packages/3-targets/3-targets/sqlite/src/core/codecs-class.ts`:
- Around line 250-264: The decode paths (async decode and decodeJson) and the
encoder path (encode and encodeJson) should validate Date objects: after
constructing a Date in decode/decodeJson, check that date.getTime() is not NaN
and throw a TypeError (same contract message) for malformed/invalid ISO strings;
in encode/encodeJson ensure the provided Date is valid (check
isFinite(date.getTime()) or !isNaN) and throw TypeError if it is an Invalid Date
before calling toISOString; update the functions named encode, decode,
encodeJson, and decodeJson in codecs-class.ts accordingly.

---

Outside diff comments:
In `@packages/2-sql/5-runtime/src/sql-context.ts`:
- Around line 493-516: The code currently caches the concrete Codec instance in
byCodecId (via voidFactory(undefined)(ctx)), causing every non-parameterized
column to share the same instance and captured ctx; instead cache the
parameterless factory function and invoke it per-column so each materialization
site gets its own Codec with its own SqlCodecInstanceContext. Concretely: in the
branch that handles non-parameterized codecs (where descriptor.factory is cast
to voidFactory), store the function returned by voidFactory(undefined) in
byCodecId (not the result of calling it with ctx), then for each column call
that cached factory with a fresh SqlCodecInstanceContext to produce
resolvedCodec; update uses of cached/voidFactory/byCodecId/resolvedCodec
accordingly so contractCodecs.forColumn() returns per-column instances.

---

Nitpick comments:
In `@examples/prisma-next-demo/test/no-emit-typed-flow.test-d.ts`:
- Around line 20-22: The test imports package internals via relative paths;
update the imports to use the package-export public API instead: replace the
relative imports that bring in the types/symbols "contract" and "sql" with their
corresponding exported package paths so the test validates the public surface
(import the "contract" type and the "sql" helper from the package exports for
prisma/prisma-no-emit rather than from ../prisma/contract and
../src/prisma-no-emit/context).

In `@packages/1-framework/1-core/framework-components/src/shared/column-spec.ts`:
- Around line 34-55: ColumnSpec currently drops the TCodecId generic from
ColumnTypeDescriptor which widens codecId literals to string; update ColumnSpec
to be generic in TCodecId and extend ColumnTypeDescriptor<TCodecId> (e.g. change
the declaration to something like interface ColumnSpec<TCodecId extends string,
R, P extends Record<string, unknown> | undefined> extends
ColumnTypeDescriptor<TCodecId>), keep the existing codecFactory and typeParams
members but use the P and R generics, and then propagate the TCodecId generic
through the column() helper signature so helper return types preserve codec ID
literals.

In `@packages/1-framework/1-core/framework-components/test/codec.types.test-d.ts`:
- Line 249: Replace the deprecated expectTypeOf(...).toMatchTypeOf usage with
the supported generic toExtend form: locate the assertion using reg
(expectTypeOf<typeof reg>().toMatchTypeOf<Map<string, AnyCodecDescriptor>>())
and change it to use toExtend with the same generic type (expectTypeOf<typeof
reg>().toExtend<Map<string, AnyCodecDescriptor>>()); ensure the generic
parameter remains Map<string, AnyCodecDescriptor> and the assertion target
remains typeof reg.

In `@packages/2-sql/2-authoring/contract-psl/test/fixtures.ts`:
- Around line 160-164: Replace plain property index checks on
targetTypesByCodecId with Object.hasOwn to avoid treating prototype keys as
valid codec ids: in the implementation returning ReturnType<CodecLookup['get']>
change the existence check from if (!targetTypesByCodecId[id]) to if
(!Object.hasOwn(targetTypesByCodecId, id)) and in the targetTypesFor method
ensure it only returns targetTypesByCodecId[id] when
Object.hasOwn(targetTypesByCodecId, id) (otherwise return undefined); leave
metaFor as-is.

In `@packages/2-sql/4-lanes/relational-core/test/utils.ts`:
- Around line 4-11: The test utility currently imports Adapter, Codec,
CodecRegistry, LoweredStatement, SelectAst and ExecutionContext from barrel
paths ('../src/exports/*'); change these to import the same symbols directly
from their concrete modules (the specific source files that define Adapter,
Codec, CodecRegistry, LoweredStatement, SelectAst and ExecutionContext) so you
avoid `/exports/` barrel imports and keep dependency boundaries explicit; update
the import statements to reference the original modules that declare those types
and remove the barrel paths.

In `@packages/3-extensions/sql-orm-client/src/types.ts`:
- Around line 302-305: The inline conditional spreads in param() should be
replaced with the shared helper ifDefined from `@prisma-next/utils/defined`:
import ifDefined and pass ParamRef.of(value, ifDefined({ codecId }, { refs }))
(or a single ifDefined call that combines the optional codecId and refs objects)
instead of the current ...(codecId !== undefined ? { codecId } : {}), ...(refs
!== undefined ? { refs } : {}); update the param() return to use ifDefined and
remove the inline conditional spreads while keeping ParamRef.of and the same
option shape.

In `@packages/3-targets/3-targets/postgres/src/core/codecs.ts`:
- Around line 55-72: The check for precision being undefined in
pgNumericRenderOutputType is unreachable because typeParams declares readonly
precision: number; remove the if (precision === undefined) return undefined;
branch and any related early-return logic; alternatively, if precision can be
missing at runtime, change the signature to readonly precision?: number and keep
the check — reference the function name pgNumericRenderOutputType and the
property typeParams.precision when making the change.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 69fcb105-9c82-4733-9268-a3018eb3c54d

📥 Commits

Reviewing files that changed from the base of the PR and between 1d8b709 and 2d4eb3b.

⛔ Files ignored due to path filters (6)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
  • projects/codec-registration-completion/plan.md is excluded by !projects/**
  • projects/codec-registration-completion/spec.md is excluded by !projects/**
  • projects/codec-registration-completion/specs/class-based-codec-design.spec.md is excluded by !projects/**
  • projects/codec-registration-completion/specs/factory-defined-codec-types.spec.md is excluded by !projects/**
  • projects/codec-registration-completion/specs/typed-codec-flow.spec.md is excluded by !projects/**
📒 Files selected for processing (218)
  • docs/README.md
  • docs/Testing Guide.md
  • docs/architecture docs/adrs/ADR 152 - Execution Plane Descriptors and Instances.md
  • docs/architecture docs/adrs/ADR 184 - Codec-owned value serialization.md
  • docs/architecture docs/adrs/ADR 186 - Codec-dispatched type rendering.md
  • docs/architecture docs/adrs/ADR 202 - Codec trait system.md
  • docs/architecture docs/adrs/ADR 204 - Single-Path Async Codec Runtime.md
  • docs/architecture docs/adrs/ADR 205 - SQL cast emission is adapter policy.md
  • docs/architecture docs/adrs/ADR 207 - Codec call context per-query AbortSignal and column metadata.md
  • docs/architecture docs/adrs/ADR 208 - Higher-order codecs for parameterized types.md
  • docs/architecture docs/adrs/ADR 209 - Mongo result-shape as a structural plan field.md
  • docs/architecture docs/subsystems/2. Contract Emitter & Types.md
  • docs/reference/codec-authoring-guide.md
  • docs/reference/community-generator-migration-analysis.md
  • docs/reference/framework-gaps.md
  • docs/reference/typescript-patterns.md
  • examples/prisma-next-demo/test/no-emit-typed-flow.test-d.ts
  • packages/1-framework/0-foundation/contract/package.json
  • packages/1-framework/0-foundation/contract/src/exports/types.ts
  • packages/1-framework/0-foundation/contract/src/standard-schema-utils.ts
  • packages/1-framework/1-core/framework-components/README.md
  • packages/1-framework/1-core/framework-components/src/control/control-stack.ts
  • packages/1-framework/1-core/framework-components/src/exports/codec.ts
  • packages/1-framework/1-core/framework-components/src/shared/codec-descriptor.ts
  • packages/1-framework/1-core/framework-components/src/shared/codec-types.ts
  • packages/1-framework/1-core/framework-components/src/shared/codec.ts
  • packages/1-framework/1-core/framework-components/src/shared/column-spec.ts
  • packages/1-framework/1-core/framework-components/src/shared/framework-components.ts
  • packages/1-framework/1-core/framework-components/test/codec-call-context.types.test-d.ts
  • packages/1-framework/1-core/framework-components/test/codec-types.types.test-d.ts
  • packages/1-framework/1-core/framework-components/test/codec.test.ts
  • packages/1-framework/1-core/framework-components/test/codec.types.test-d.ts
  • packages/1-framework/1-core/framework-components/test/control-stack.test.ts
  • packages/1-framework/2-authoring/contract/README.md
  • packages/1-framework/2-authoring/contract/src/descriptors.ts
  • packages/1-framework/2-authoring/contract/src/index.ts
  • packages/1-framework/2-authoring/contract/test/descriptors.test.ts
  • packages/1-framework/2-authoring/ids/package.json
  • packages/1-framework/2-authoring/ids/src/index.ts
  • packages/1-framework/3-tooling/cli/src/control-api/contract-enrichment.ts
  • packages/1-framework/3-tooling/cli/test/config-types.test.ts
  • packages/1-framework/3-tooling/cli/test/control-api/contract-enrichment.test.ts
  • packages/1-framework/3-tooling/emitter/src/domain-type-generation.ts
  • packages/1-framework/3-tooling/emitter/test/domain-type-generation.test.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/README.md
  • packages/2-mongo-family/1-foundation/mongo-codec/src/codec-registry.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/src/codecs.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/src/exports/index.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs-ctx.test-d.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs-ctx.test.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs.test-d.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs.test.ts
  • packages/2-mongo-family/2-authoring/contract-psl/src/derive-json-schema.ts
  • packages/2-mongo-family/2-authoring/contract-psl/test/derive-json-schema.test.ts
  • packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.polymorphism.test.ts
  • packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.test.ts
  • packages/2-mongo-family/7-runtime/README.md
  • packages/2-mongo-family/7-runtime/src/mongo-execution-stack.ts
  • packages/2-mongo-family/7-runtime/test/codecs/decoding.test.ts
  • packages/2-mongo-family/7-runtime/test/decode.integration.test.ts
  • packages/2-mongo-family/7-runtime/test/mongo-execution-stack.test.ts
  • packages/2-mongo-family/7-runtime/test/mongo-middleware.test.ts
  • packages/2-mongo-family/7-runtime/test/mongo-runtime-abort.test.ts
  • packages/2-sql/2-authoring/contract-psl/src/provider.ts
  • packages/2-sql/2-authoring/contract-psl/test/fixtures.ts
  • packages/2-sql/2-authoring/contract-psl/test/provider.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/ts-psl-parity.test.ts
  • packages/2-sql/2-authoring/contract-ts/src/contract-definition.ts
  • packages/2-sql/2-authoring/contract-ts/src/contract-dsl.ts
  • packages/2-sql/2-authoring/contract-ts/src/contract-lowering.ts
  • packages/2-sql/2-authoring/contract-ts/test/config-types.test.ts
  • packages/2-sql/2-authoring/contract-ts/test/contract-builder.contract-definition.test.ts
  • packages/2-sql/2-authoring/contract-ts/test/contract-builder.value-objects.test.ts
  • packages/2-sql/2-authoring/contract-ts/test/helpers/column-descriptor.ts
  • packages/2-sql/3-tooling/emitter/test/emitter-hook.typeref-resolver.test.ts
  • packages/2-sql/4-lanes/relational-core/README.md
  • packages/2-sql/4-lanes/relational-core/package.json
  • packages/2-sql/4-lanes/relational-core/src/ast/codec-types.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs-class.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/types.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/validate-param-refs.ts
  • packages/2-sql/4-lanes/relational-core/src/exports/ast.ts
  • packages/2-sql/4-lanes/relational-core/src/expression.ts
  • packages/2-sql/4-lanes/relational-core/src/query-lane-context.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-factory-ctx.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-factory-ctx.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-factory.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-factory.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-types.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/refs-propagation.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codecs-class.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codecs-class.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codecs.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/test-codec.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/test-helpers.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/validate-param-refs.test.ts
  • packages/2-sql/4-lanes/relational-core/test/expression.test.ts
  • packages/2-sql/4-lanes/relational-core/test/typed-codec-flow.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/utils.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/builder-base.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/expression-impl.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/field-proxy.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/functions.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/mutation-impl.ts
  • packages/2-sql/4-lanes/sql-builder/test/runtime/field-proxy.test.ts
  • packages/2-sql/4-lanes/sql-builder/test/runtime/functions.test.ts
  • packages/2-sql/5-runtime/src/codecs/decoding.ts
  • packages/2-sql/5-runtime/src/codecs/encoding.ts
  • packages/2-sql/5-runtime/src/codecs/json-schema-validation.ts
  • packages/2-sql/5-runtime/src/sql-context.ts
  • packages/2-sql/5-runtime/src/sql-runtime.ts
  • packages/2-sql/5-runtime/test/before-compile-chain.test.ts
  • packages/2-sql/5-runtime/test/codec-async.test.ts
  • packages/2-sql/5-runtime/test/codec-decode-ctx.test.ts
  • packages/2-sql/5-runtime/test/codec-encode-ctx.test.ts
  • packages/2-sql/5-runtime/test/contract-codec-registry.test.ts
  • packages/2-sql/5-runtime/test/encoding-dispatch.test.ts
  • packages/2-sql/5-runtime/test/execution-stack.test.ts
  • packages/2-sql/5-runtime/test/json-schema-validation.test.ts
  • packages/2-sql/5-runtime/test/mutation-default-generators.test.ts
  • packages/2-sql/5-runtime/test/parameterized-types.test.ts
  • packages/2-sql/5-runtime/test/seeded-secret-codec.ts
  • packages/2-sql/5-runtime/test/sql-context.test.ts
  • packages/2-sql/5-runtime/test/sql-runtime-abort.test.ts
  • packages/2-sql/5-runtime/test/sql-runtime.test.ts
  • packages/2-sql/5-runtime/test/test-codec.ts
  • packages/2-sql/5-runtime/test/utils.ts
  • packages/3-extensions/arktype-json/README.md
  • packages/3-extensions/arktype-json/src/core/arktype-json-codec-class.ts
  • packages/3-extensions/arktype-json/src/core/arktype-json-codec.ts
  • packages/3-extensions/arktype-json/src/core/pack-meta.ts
  • packages/3-extensions/arktype-json/src/exports/codecs.ts
  • packages/3-extensions/arktype-json/src/exports/column-types.ts
  • packages/3-extensions/arktype-json/src/exports/control.ts
  • packages/3-extensions/arktype-json/src/exports/runtime.ts
  • packages/3-extensions/arktype-json/test/arktype-json-codec-class.test.ts
  • packages/3-extensions/arktype-json/test/arktype-json-codec-class.types.test-d.ts
  • packages/3-extensions/arktype-json/test/arktype-json-codec.test-d.ts
  • packages/3-extensions/arktype-json/test/arktype-json-codec.test.ts
  • packages/3-extensions/arktype-json/test/extension-descriptors.test.ts
  • packages/3-extensions/pgvector/src/core/codecs-class.ts
  • packages/3-extensions/pgvector/src/core/codecs.ts
  • packages/3-extensions/pgvector/src/core/descriptor-meta.ts
  • packages/3-extensions/pgvector/src/exports/column-types.ts
  • packages/3-extensions/pgvector/src/exports/runtime.ts
  • packages/3-extensions/pgvector/src/types/codec-types.ts
  • packages/3-extensions/pgvector/test/codec-render-output-type.test.ts
  • packages/3-extensions/pgvector/test/codecs-class.types.test-d.ts
  • packages/3-extensions/pgvector/test/codecs.test.ts
  • packages/3-extensions/pgvector/test/operations.test.ts
  • packages/3-extensions/pgvector/test/typed-descriptor-flow.test-d.ts
  • packages/3-extensions/sql-orm-client/src/query-plan-mutations.ts
  • packages/3-extensions/sql-orm-client/src/types.ts
  • packages/3-extensions/sql-orm-client/src/where-binding.ts
  • packages/3-extensions/sql-orm-client/test/codec-async.types.test-d.ts
  • packages/3-extensions/sql-orm-client/test/filters.test.ts
  • packages/3-extensions/sql-orm-client/test/integration/codec-async.test.ts
  • packages/3-extensions/sql-orm-client/test/integration/create.test.ts
  • packages/3-extensions/sql-orm-client/test/model-accessor.test.ts
  • packages/3-extensions/sql-orm-client/test/query-plan-mutations.test.ts
  • packages/3-extensions/sql-orm-client/test/repository.test.ts
  • packages/3-extensions/sql-orm-client/test/rich-filters-and-where.test.ts
  • packages/3-extensions/sql-orm-client/test/test-codec.ts
  • packages/3-mongo-target/1-mongo-target/src/exports/runtime.ts
  • packages/3-mongo-target/2-mongo-adapter/src/core/codecs.ts
  • packages/3-mongo-target/2-mongo-adapter/src/exports/control.ts
  • packages/3-mongo-target/2-mongo-adapter/src/exports/runtime.ts
  • packages/3-mongo-target/2-mongo-adapter/test/codecs.test.ts
  • packages/3-mongo-target/2-mongo-adapter/test/lowering.test.ts
  • packages/3-mongo-target/2-mongo-adapter/test/mongo-adapter-ctx.test.ts
  • packages/3-mongo-target/2-mongo-adapter/test/mongo-adapter.test.ts
  • packages/3-mongo-target/2-mongo-adapter/test/resolve-value-ctx.test.ts
  • packages/3-mongo-target/2-mongo-adapter/test/resolve-value.test.ts
  • packages/3-targets/3-targets/postgres/package.json
  • packages/3-targets/3-targets/postgres/src/core/codecs-class.ts
  • packages/3-targets/3-targets/postgres/src/core/codecs.ts
  • packages/3-targets/3-targets/postgres/src/core/descriptor-meta.ts
  • packages/3-targets/3-targets/postgres/src/exports/codec-types.ts
  • packages/3-targets/3-targets/postgres/src/exports/codecs.ts
  • packages/3-targets/3-targets/postgres/src/exports/runtime.ts
  • packages/3-targets/3-targets/postgres/test/codec-render-output-type.test.ts
  • packages/3-targets/3-targets/postgres/test/codecs-class.test.ts
  • packages/3-targets/3-targets/postgres/test/codecs-class.types.test-d.ts
  • packages/3-targets/3-targets/postgres/test/codecs.test.ts
  • packages/3-targets/3-targets/postgres/test/typed-descriptor-flow.test-d.ts
  • packages/3-targets/3-targets/sqlite/src/core/codecs-class.ts
  • packages/3-targets/3-targets/sqlite/src/core/codecs.ts
  • packages/3-targets/3-targets/sqlite/src/core/descriptor-meta.ts
  • packages/3-targets/3-targets/sqlite/src/core/runtime-target.ts
  • packages/3-targets/3-targets/sqlite/src/exports/codec-types.ts
  • packages/3-targets/3-targets/sqlite/src/exports/codecs.ts
  • packages/3-targets/3-targets/sqlite/test/codecs-class.types.test-d.ts
  • packages/3-targets/3-targets/sqlite/test/typed-descriptor-flow.test-d.ts
  • packages/3-targets/6-adapters/postgres/README.md
  • packages/3-targets/6-adapters/postgres/src/core/adapter.ts
  • packages/3-targets/6-adapters/postgres/src/core/codec-lookup.ts
  • packages/3-targets/6-adapters/postgres/src/core/descriptor-meta.ts
  • packages/3-targets/6-adapters/postgres/src/core/sql-renderer.ts
  • packages/3-targets/6-adapters/postgres/src/exports/column-types.ts
  • packages/3-targets/6-adapters/postgres/src/exports/runtime.ts
  • packages/3-targets/6-adapters/postgres/test/adapter.test.ts
  • packages/3-targets/6-adapters/postgres/test/descriptor-parity.test.ts
  • packages/3-targets/6-adapters/postgres/test/sql-renderer.cast-policy.test.ts
  • packages/3-targets/6-adapters/postgres/test/test-codec.ts
  • packages/3-targets/6-adapters/sqlite/README.md
  • packages/3-targets/6-adapters/sqlite/src/core/adapter.ts
  • packages/3-targets/6-adapters/sqlite/src/core/runtime-adapter.ts
  • packages/3-targets/6-adapters/sqlite/src/exports/codec-types.ts
  • packages/3-targets/6-adapters/sqlite/test/codecs.test.ts
  • test/integration/test/authoring/parity/ts-psl-parity.real-packs.test.ts
  • test/integration/test/contract-builder.test.ts
  • test/integration/test/cross-package/cross-family-codec.test.ts
  • test/integration/test/cross-package/test-codec.ts
  • test/integration/test/mongo/migration-psl-authoring.test.ts
  • test/integration/test/pgvector.test.ts
  • test/utils/README.md
  • test/utils/src/column-descriptors.ts
💤 Files with no reviewable changes (11)
  • packages/2-mongo-family/7-runtime/test/decode.integration.test.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs-ctx.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-types.test.ts
  • packages/3-extensions/pgvector/src/core/codecs.ts
  • packages/2-sql/5-runtime/src/codecs/json-schema-validation.ts
  • packages/3-extensions/arktype-json/src/core/arktype-json-codec.ts
  • packages/3-extensions/arktype-json/test/arktype-json-codec.test-d.ts
  • packages/1-framework/2-authoring/contract/src/descriptors.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs-ctx.test-d.ts
  • packages/2-sql/5-runtime/test/json-schema-validation.test.ts
  • packages/3-extensions/arktype-json/test/arktype-json-codec.test.ts

Comment thread docs/reference/codec-authoring-guide.md Outdated
Comment thread examples/prisma-next-demo/test/no-emit-typed-flow.test-d.ts
Comment thread packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs-class.ts Outdated
Comment thread packages/3-extensions/arktype-json/test/arktype-json-codec.test.ts
Comment thread packages/3-extensions/arktype-json/test/arktype-json-codec.types.test-d.ts Outdated
Comment thread packages/3-extensions/sql-orm-client/src/types.ts
Comment thread packages/3-targets/3-targets/postgres/src/core/codecs-class.ts Outdated
Comment thread packages/3-targets/3-targets/sqlite/src/core/codecs-class.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

♻️ Duplicate comments (5)
packages/3-extensions/arktype-json/test/arktype-json-codec-class.types.test-d.ts (1)

140-142: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Use the approved matcher for .test-d.ts type compatibility assertions.

Line 140 uses deprecated toMatchTypeOf; switch to toExtend for this subtype-style check.

♻️ Proposed fix
-  expectTypeOf(col).toMatchTypeOf<
+  expectTypeOf(col).toExtend<
     ColumnSpec<ArktypeJsonCodecClass<{ name: string; price: number }>, ArktypeJsonTypeParams>
   >();
#!/bin/bash
# Verify deprecated matcher usage in .test-d.ts files.
rg -n --glob '**/*.test-d.ts' '\.toMatchTypeOf\s*<'

As per coding guidelines, "**/*.test-d.ts: Do not use the deprecated toMatchTypeOf() matcher in Vitest's expectTypeOf API. Use toExtend() instead."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@packages/3-extensions/arktype-json/test/arktype-json-codec-class.types.test-d.ts`
around lines 140 - 142, Replace the deprecated matcher usage: locate the
expectTypeOf assertion that references ColumnSpec<ArktypeJsonCodecClass<{ name:
string; price: number }>, ArktypeJsonTypeParams> (the expectTypeOf(col) line)
and change the matcher from toMatchTypeOf<...>() to toExtend<...>() so the
subtype-style compatibility check uses the approved Vitest matcher for
.test-d.ts files.
packages/3-extensions/arktype-json/src/core/arktype-json-codec-class.ts (1)

144-147: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Replace the double-cast in schema rehydration with a predicate-based narrow.

Line 146 force-casts ark.schema(jsonIr) with as unknown as ArktypeSchemaLike, which bypasses static safety and can mask shape drift.

♻️ Proposed fix
 function rehydrateSchema(jsonIr: object): ArktypeSchemaLike {
   try {
-    return ark.schema(jsonIr) as unknown as ArktypeSchemaLike;
+    const schema = ark.schema(jsonIr);
+    if (!isArktypeSchemaLike(schema)) {
+      throw new Error('Rehydrated schema is not callable with expression metadata');
+    }
+    return schema;
   } catch (error) {
     throw runtimeError(
       'RUNTIME.JSON_SCHEMA_VALIDATION_FAILED',
       `Failed to rehydrate arktype schema from contract IR: ${error instanceof Error ? error.message : String(error)}`,
       { codecId: ARKTYPE_JSON_CODEC_ID, jsonIr },
     );
   }
 }
In current Arktype docs/types, what does `ark.schema(jsonIr)` return, and is the return value guaranteed to be callable with an `expression: string` property?

As per coding guidelines, "packages/**/*.{ts,tsx}: No blind casts in production code: as unknown as X is forbidden outside tests. Prefer type predicates or fix the type surface."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/3-extensions/arktype-json/src/core/arktype-json-codec-class.ts`
around lines 144 - 147, The rehydrateSchema function silently force-casts
ark.schema(jsonIr) to ArktypeSchemaLike with "as unknown as", which violates the
no-blind-casts rule; replace the double-cast with a runtime type-narrow: call
ark.schema(jsonIr) into a local const (no cast), then implement and use a type
predicate/is-check (for example isArktypeSchemaLike) that verifies the returned
value is callable and has the expected shape (e.g., a function and the
"expression" property of type string or other required members), throw a clear
error if the check fails, and only then return the value typed as
ArktypeSchemaLike; reference rehydrateSchema and ark.schema when locating code
to change.
packages/3-extensions/arktype-json/test/arktype-json-codec-class.test.ts (1)

75-79: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Replace as any + lint suppression with @ts-expect-error in the guard test.

Lines 77-78 currently bypass both typing and lint policy; this negative-path test can express intent without any or biome-ignore.

♻️ Proposed fix
   it('rejects non-callable schema lookalikes at the call site', () => {
     const notASchema = { foo: 'bar' };
-    // biome-ignore lint/suspicious/noExplicitAny: deliberately malformed input for the call-site guard
-    expect(() => arktypeJsonColumn(notASchema as any)).toThrow(/callable arktype Type/);
+    // `@ts-expect-error` -- intentionally passing non-callable value to test runtime guard
+    expect(() => arktypeJsonColumn(notASchema)).toThrow(/callable arktype Type/);
   });
#!/bin/bash
# Verify explicit any and biome suppressions in this test file.
rg -n 'biome-ignore|as any|@ts-expect-error' packages/3-extensions/arktype-json/test/arktype-json-codec-class.test.ts -C2

As per coding guidelines, "Never use any type", "Never suppress biome lints", and "Use @ts-expect-error with a short reason in tests."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/3-extensions/arktype-json/test/arktype-json-codec-class.test.ts`
around lines 75 - 79, The test currently silences type + lint rules by using "as
any" and a "biome-ignore" comment; replace that with a TypeScript compile-time
suppression using `@ts-expect-error` plus a short reason above the offending call
to arktypeJsonColumn so the test still asserts the runtime guard without using
any/biome ignores. Locate the failing test in arktype-json-codec-class.test.ts
where arktypeJsonColumn(notASchema as any) is called and remove the "as any"
cast and the biome-ignore, adding a single-line "@ts-expect-error TS-EXPLAIN:
deliberate malformed input to exercise call-site guard" immediately above the
call.
packages/3-targets/3-targets/sqlite/src/core/codecs-class.ts (1)

245-258: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Reject invalid Date values at the codec boundary.

new Date(wire) / new Date(json) can produce an Invalid Date, and toISOString() will also fail if callers hand this codec an invalid Date. Validating here keeps malformed storage values and contract JSON from escaping as poisoned Date instances.

🐛 Minimal validation
 export class SqliteDatetimeCodec extends CodecImpl<
@@
 > {
   async encode(value: Date, _ctx: CodecCallContext): Promise<string> {
+    if (Number.isNaN(value.getTime())) {
+      throw new TypeError('sqlite/datetime@1 input value must be a valid Date');
+    }
     return value.toISOString();
   }
   async decode(wire: string, _ctx: CodecCallContext): Promise<Date> {
-    return new Date(wire);
+    const date = new Date(wire);
+    if (Number.isNaN(date.getTime())) {
+      throw new TypeError('sqlite/datetime@1 wire value must be a valid ISO-8601 string');
+    }
+    return date;
   }
   encodeJson(value: Date): JsonValue {
+    if (Number.isNaN(value.getTime())) {
+      throw new TypeError('sqlite/datetime@1 contract value must be a valid Date');
+    }
     return value.toISOString();
   }
   decodeJson(json: JsonValue): Date {
     if (typeof json !== 'string') {
       throw new TypeError('sqlite/datetime@1 contract value must be an ISO-8601 string');
     }
-    return new Date(json);
+    const date = new Date(json);
+    if (Number.isNaN(date.getTime())) {
+      throw new TypeError('sqlite/datetime@1 contract value must be a valid ISO-8601 string');
+    }
+    return date;
   }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/3-targets/3-targets/sqlite/src/core/codecs-class.ts` around lines
245 - 258, The codec must reject invalid Date instances and non-strings: in
encode and encodeJson (functions encode(value: Date, _ctx: CodecCallContext) and
encodeJson(value: Date)) check that value is a Date (instanceof Date) and that
Number.isFinite(value.getTime())/!Number.isNaN(value.getTime()) before calling
toISOString(), and throw a TypeError if not; in decode and decodeJson
(decode(wire: string, _ctx: CodecCallContext) and decodeJson(json: JsonValue))
ensure the input is a string, construct the Date, then validate the produced
Date with Number.isFinite(date.getTime())/!Number.isNaN(...) and throw a
TypeError for invalid dates instead of returning them.
packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs-class.ts (1)

67-76: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

sqlCharColumn() / sqlVarcharColumn() still expose an impossible params shape.

lengthParamsSchema requires length, but LengthParams makes it optional and both helpers default to {}. That lets callers build column specs that this same descriptor later rejects during params validation. Either require length end-to-end, or relax the schema if bare char / varchar is intentionally supported.

🐛 Minimal fix
-type LengthParams = { readonly length?: number };
+type LengthParams = { readonly length: number };

-export const sqlCharColumn = (params: LengthParams = {}) =>
+export const sqlCharColumn = (params: LengthParams) =>
   column(sqlCharDescriptor.factory(params), sqlCharDescriptor.codecId, params, 'char');

-export const sqlVarcharColumn = (params: LengthParams = {}) =>
+export const sqlVarcharColumn = (params: LengthParams) =>
   column(sqlVarcharDescriptor.factory(params), sqlVarcharDescriptor.codecId, params, 'varchar');

Also applies to: 245-246, 290-291

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs-class.ts` around
lines 67 - 76, The params shape is inconsistent: lengthParamsSchema currently
requires length but the TypeScript type LengthParams and the
sqlCharColumn/sqlVarcharColumn helpers treat length as optional and default to
{}. Fix by making the contract consistent — either (A) relax lengthParamsSchema
to allow an optional length (e.g., make the length rule accept undefined or mark
it optional) so it matches LengthParams and the default {} behavior, or (B) make
LengthParams require length and update sqlCharColumn/sqlVarcharColumn to require
callers to supply length (and remove the default {}). Locate and update
lengthParamsSchema, the LengthParams type, and the
sqlCharColumn/sqlVarcharColumn call sites to implement the chosen option so
params validation no longer rejects valid inputs.
🧹 Nitpick comments (4)
packages/3-targets/6-adapters/postgres/src/core/adapter.ts (1)

44-60: ⚡ Quick win

Don’t leave the factory(undefined) invariant implicit.

This block now depends on every descriptor in postgresCodecRegistry being safely materializable without params. That may be true for current builtins, but it is only enforced by comments right now. Please move this through a small helper owned next to postgresCodecRegistry or add a fail-fast assertion here so a future param-sensitive descriptor does not silently instantiate the wrong runtime codec.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/3-targets/6-adapters/postgres/src/core/adapter.ts` around lines 44 -
60, The code silently calls factory(undefined) for each descriptor from
postgresCodecRegistry when constructing codecRegistry, which assumes every
descriptor is paramless; add a fail-fast check or helper next to
postgresCodecRegistry to enforce/verify that a descriptor is materializable
without params before calling factory(undefined). Concretely, introduce a small
predicate/helper (e.g., isParamlessDescriptor) or add an assertion in the
codecRegistry initializer that inspects the descriptor shape and throws a clear
error if params are required, and then only call (descriptor.factory)(undefined)
(or use the helper) to produce the codec instance; reference codecRegistry,
postgresCodecRegistry, CodecInstanceContext and the current factory(undefined)
usage when making the change.
packages/3-targets/6-adapters/sqlite/src/core/adapter.ts (1)

55-70: 🏗️ Heavy lift

Don't materialize every descriptor with factory(undefined).

sqliteCodecRegistry now includes parameterized SQL descriptors, but this loop hard-casts every factory to accept unknown and instantiates it with undefined. The adapter registry therefore only works for descriptors whose runtime instances happen to ignore params; the first param-sensitive codec added here will be mis-materialized. Please keep this surface descriptor-based, or restrict this fallback registry to descriptors whose params are truly void.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/3-targets/6-adapters/sqlite/src/core/adapter.ts` around lines 55 -
70, The current codecRegistry eagerly materializes every descriptor by calling
descriptor.factory(undefined), which mis-instantiates parameterized descriptors
from sqliteCodecRegistry; change this to preserve descriptor-based entries and
only instantiate codecs when they are truly parameterless: in the codecRegistry
initialization (and related logic around codecRegistry, sqliteCodecRegistry,
CodecInstanceContext and factory), avoid calling factory(undefined) for all
descriptors—instead detect parameterized descriptors (e.g., via a param-type
flag or factory arity) and either keep the original descriptor in the registry
or only call factory() for descriptors known to accept no params; ensure the
fallback registry only materializes codecs whose params are void so
parameterized codecs remain descriptor-based.
packages/3-targets/3-targets/postgres/test/codecs.test.ts (1)

75-82: ⚡ Quick win

Don't bypass parameterized descriptor factories here.

descriptor.factory(undefined as never) sidesteps the public params contract for character, numeric, timestamp, enum, and the other parameterized descriptors in this table. The suite still checks encode/decode behavior, but it no longer proves those codecs can be constructed through their supported API shape. A small paramsByScalar map, or separate helpers for parameterized vs non-parameterized codecs, would keep these tests aligned with the descriptor-first surface.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/3-targets/3-targets/postgres/test/codecs.test.ts` around lines 75 -
82, The helper codecForScalar currently calls descriptor.factory(undefined as
never) which bypasses the public params contract for parameterized descriptors;
change codecForScalar to supply real params for parameterized descriptors (e.g.
via a small paramsByScalar map or conditional helpers) and call
descriptor.factory(params) for those scalars, falling back to
descriptor.factory() or descriptor.factory(undefined) only for true
non-parameterized descriptors so that descriptorByScalar/descriptor.factory and
SYNTH_CTX are exercised via the intended public API shape.
packages/3-targets/3-targets/sqlite/src/exports/codec-types.ts (1)

11-45: ⚡ Quick win

Keep src/exports/codec-types.ts as a thin re-export surface.

codecDescriptorMap and Resolve make this export file a second source of truth for SQLite codec membership. That raises the odds of CodecTypes drifting from the core registry/list when the next codec is added or removed. Please move the map/type derivation into ../core/... and re-export the final alias from here so the public entrypoint stays aligned with the package’s single descriptor source.

♻️ Suggested shape
-import type { ExtractCodecTypes } from '@prisma-next/sql-relational-core/ast';
-import {
-  sqlCharDescriptor,
-  sqlFloatDescriptor,
-  sqlIntDescriptor,
-  sqlVarcharDescriptor,
-} from '@prisma-next/sql-relational-core/ast';
 import type { JsonValue } from '../core/codecs';
-import {
-  sqliteBigintDescriptor,
-  sqliteBlobDescriptor,
-  sqliteDatetimeDescriptor,
-  sqliteIntegerDescriptor,
-  sqliteJsonDescriptor,
-  sqliteRealDescriptor,
-  sqliteTextDescriptor,
-} from '../core/codecs-class';
-
-const codecDescriptorMap = {
-  char: sqlCharDescriptor,
-  varchar: sqlVarcharDescriptor,
-  int: sqlIntDescriptor,
-  float: sqlFloatDescriptor,
-  text: sqliteTextDescriptor,
-  integer: sqliteIntegerDescriptor,
-  real: sqliteRealDescriptor,
-  blob: sqliteBlobDescriptor,
-  datetime: sqliteDatetimeDescriptor,
-  json: sqliteJsonDescriptor,
-  bigint: sqliteBigintDescriptor,
-} as const;
-
-type Resolve<T> = { readonly [K in keyof T]: { readonly [P in keyof T[K]]: T[K][P] } };
-
-export type CodecTypes = Resolve<ExtractCodecTypes<typeof codecDescriptorMap>>;
+export type { CodecTypes } from '../core/codec-types';
 export type { JsonValue };

As per coding guidelines, packages/**/src/exports/{adapter,codec-types,types}.ts re-export files must re-export from core without adding additional logic.

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/2-sql/4-lanes/relational-core/src/codec-descriptor-registry.ts`:
- Around line 31-39: The registry currently overwrites duplicate codecId entries
causing inconsistent state; before calling byId.set(descriptor.codecId, widened)
in the loop over allDescriptors (where widened is cast to AnyDescriptor), check
if byId.has(descriptor.codecId) and throw a clear error (including the
conflicting codecId and descriptor identity) to fail-fast on duplicates; only
proceed to add to byTargetType when the codecId is not already present (so byId
and byTargetType remain consistent and descriptorFor(id) will match target-type
lists).

In `@packages/3-extensions/pgvector/src/core/codecs-class.ts`:
- Around line 82-118: The PgVectorCodec produced by factory() must retain
params.length (the declared dimension) and validate input across all ingress
paths: modify factory() to store the expected length on the PgVectorCodec
instance, add a single reused validator function (used by encode, decode, and
decodeJson) that checks the value is an array of numbers and that its length
equals the stored dimension, and update encodeJson/decodeJson/decode/encode to
call that validator and throw descriptive errors for wrong-dimension or
non-numeric entries; ensure contractCodecs.forColumn(table, column) returns a
codec that enforces the declared vector length rather than ignoring
params.length.

In `@packages/3-targets/3-targets/postgres/src/exports/codec-types.ts`:
- Around line 19-86: The file defines codecDescriptorMap, Resolve, and
CodecTypes inline which violates the export-only rule; move the
codecDescriptorMap, Resolve type helper, and the ExtractCodecTypes processing
into a new or existing module under src/core (e.g., export the computed type
there) and then change src/exports/codec-types.ts to only re-export the public
type (export type { CodecTypes } from '../core/...') so the exports file
contains no computation or logic and only exposes the type symbol CodecTypes.

In `@packages/3-targets/3-targets/sqlite/src/core/codecs-class.ts`:
- Around line 204-211: The encodeJson and decodeJson methods currently use
Node-only Buffer; replace that with a runtime-neutral base64 utility so src/core
stays platform-agnostic: implement or import cross-platform helpers (e.g.,
uint8ArrayToBase64 and base64ToUint8Array) that use Web APIs (atob/btoa or
TextEncoder/TextDecoder) and fall back to Buffer only when necessary, then
update encodeJson(value: Uint8Array) to return uint8ArrayToBase64(value) and
decodeJson(json: JsonValue) to validate string and return
base64ToUint8Array(json); keep the function names encodeJson and decodeJson
unchanged.

---

Duplicate comments:
In `@packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs-class.ts`:
- Around line 67-76: The params shape is inconsistent: lengthParamsSchema
currently requires length but the TypeScript type LengthParams and the
sqlCharColumn/sqlVarcharColumn helpers treat length as optional and default to
{}. Fix by making the contract consistent — either (A) relax lengthParamsSchema
to allow an optional length (e.g., make the length rule accept undefined or mark
it optional) so it matches LengthParams and the default {} behavior, or (B) make
LengthParams require length and update sqlCharColumn/sqlVarcharColumn to require
callers to supply length (and remove the default {}). Locate and update
lengthParamsSchema, the LengthParams type, and the
sqlCharColumn/sqlVarcharColumn call sites to implement the chosen option so
params validation no longer rejects valid inputs.

In `@packages/3-extensions/arktype-json/src/core/arktype-json-codec-class.ts`:
- Around line 144-147: The rehydrateSchema function silently force-casts
ark.schema(jsonIr) to ArktypeSchemaLike with "as unknown as", which violates the
no-blind-casts rule; replace the double-cast with a runtime type-narrow: call
ark.schema(jsonIr) into a local const (no cast), then implement and use a type
predicate/is-check (for example isArktypeSchemaLike) that verifies the returned
value is callable and has the expected shape (e.g., a function and the
"expression" property of type string or other required members), throw a clear
error if the check fails, and only then return the value typed as
ArktypeSchemaLike; reference rehydrateSchema and ark.schema when locating code
to change.

In `@packages/3-extensions/arktype-json/test/arktype-json-codec-class.test.ts`:
- Around line 75-79: The test currently silences type + lint rules by using "as
any" and a "biome-ignore" comment; replace that with a TypeScript compile-time
suppression using `@ts-expect-error` plus a short reason above the offending call
to arktypeJsonColumn so the test still asserts the runtime guard without using
any/biome ignores. Locate the failing test in arktype-json-codec-class.test.ts
where arktypeJsonColumn(notASchema as any) is called and remove the "as any"
cast and the biome-ignore, adding a single-line "@ts-expect-error TS-EXPLAIN:
deliberate malformed input to exercise call-site guard" immediately above the
call.

In
`@packages/3-extensions/arktype-json/test/arktype-json-codec-class.types.test-d.ts`:
- Around line 140-142: Replace the deprecated matcher usage: locate the
expectTypeOf assertion that references ColumnSpec<ArktypeJsonCodecClass<{ name:
string; price: number }>, ArktypeJsonTypeParams> (the expectTypeOf(col) line)
and change the matcher from toMatchTypeOf<...>() to toExtend<...>() so the
subtype-style compatibility check uses the approved Vitest matcher for
.test-d.ts files.

In `@packages/3-targets/3-targets/sqlite/src/core/codecs-class.ts`:
- Around line 245-258: The codec must reject invalid Date instances and
non-strings: in encode and encodeJson (functions encode(value: Date, _ctx:
CodecCallContext) and encodeJson(value: Date)) check that value is a Date
(instanceof Date) and that
Number.isFinite(value.getTime())/!Number.isNaN(value.getTime()) before calling
toISOString(), and throw a TypeError if not; in decode and decodeJson
(decode(wire: string, _ctx: CodecCallContext) and decodeJson(json: JsonValue))
ensure the input is a string, construct the Date, then validate the produced
Date with Number.isFinite(date.getTime())/!Number.isNaN(...) and throw a
TypeError for invalid dates instead of returning them.

---

Nitpick comments:
In `@packages/3-targets/3-targets/postgres/test/codecs.test.ts`:
- Around line 75-82: The helper codecForScalar currently calls
descriptor.factory(undefined as never) which bypasses the public params contract
for parameterized descriptors; change codecForScalar to supply real params for
parameterized descriptors (e.g. via a small paramsByScalar map or conditional
helpers) and call descriptor.factory(params) for those scalars, falling back to
descriptor.factory() or descriptor.factory(undefined) only for true
non-parameterized descriptors so that descriptorByScalar/descriptor.factory and
SYNTH_CTX are exercised via the intended public API shape.

In `@packages/3-targets/6-adapters/postgres/src/core/adapter.ts`:
- Around line 44-60: The code silently calls factory(undefined) for each
descriptor from postgresCodecRegistry when constructing codecRegistry, which
assumes every descriptor is paramless; add a fail-fast check or helper next to
postgresCodecRegistry to enforce/verify that a descriptor is materializable
without params before calling factory(undefined). Concretely, introduce a small
predicate/helper (e.g., isParamlessDescriptor) or add an assertion in the
codecRegistry initializer that inspects the descriptor shape and throws a clear
error if params are required, and then only call (descriptor.factory)(undefined)
(or use the helper) to produce the codec instance; reference codecRegistry,
postgresCodecRegistry, CodecInstanceContext and the current factory(undefined)
usage when making the change.

In `@packages/3-targets/6-adapters/sqlite/src/core/adapter.ts`:
- Around line 55-70: The current codecRegistry eagerly materializes every
descriptor by calling descriptor.factory(undefined), which mis-instantiates
parameterized descriptors from sqliteCodecRegistry; change this to preserve
descriptor-based entries and only instantiate codecs when they are truly
parameterless: in the codecRegistry initialization (and related logic around
codecRegistry, sqliteCodecRegistry, CodecInstanceContext and factory), avoid
calling factory(undefined) for all descriptors—instead detect parameterized
descriptors (e.g., via a param-type flag or factory arity) and either keep the
original descriptor in the registry or only call factory() for descriptors known
to accept no params; ensure the fallback registry only materializes codecs whose
params are void so parameterized codecs remain descriptor-based.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 395e4d68-7371-4142-b775-7022bfe445bb

📥 Commits

Reviewing files that changed from the base of the PR and between 2d4eb3b and 583a8e9.

📒 Files selected for processing (46)
  • packages/2-sql/4-lanes/relational-core/package.json
  • packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs-class.ts
  • packages/2-sql/4-lanes/relational-core/src/codec-descriptor-registry.ts
  • packages/2-sql/4-lanes/relational-core/src/exports/codec-descriptor-registry.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codecs-class.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codecs-class.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codecs.test.ts
  • packages/2-sql/4-lanes/relational-core/test/typed-codec-flow.test-d.ts
  • packages/2-sql/4-lanes/relational-core/tsdown.config.ts
  • packages/2-sql/5-runtime/src/sql-context.ts
  • packages/3-extensions/arktype-json/src/core/arktype-json-codec-class.ts
  • packages/3-extensions/arktype-json/src/core/pack-meta.ts
  • packages/3-extensions/arktype-json/src/exports/codecs.ts
  • packages/3-extensions/arktype-json/test/arktype-json-codec-class.test.ts
  • packages/3-extensions/arktype-json/test/arktype-json-codec-class.types.test-d.ts
  • packages/3-extensions/arktype-json/test/extension-descriptors.test.ts
  • packages/3-extensions/pgvector/src/core/codecs-class.ts
  • packages/3-extensions/pgvector/src/core/descriptor-meta.ts
  • packages/3-extensions/pgvector/src/core/registry.ts
  • packages/3-extensions/pgvector/src/exports/runtime.ts
  • packages/3-extensions/pgvector/test/codec-render-output-type.test.ts
  • packages/3-extensions/pgvector/test/codecs-class.types.test-d.ts
  • packages/3-extensions/pgvector/test/codecs.test.ts
  • packages/3-extensions/pgvector/test/typed-descriptor-flow.test-d.ts
  • packages/3-targets/3-targets/postgres/src/core/codecs-class.ts
  • packages/3-targets/3-targets/postgres/src/core/registry.ts
  • packages/3-targets/3-targets/postgres/src/exports/codec-types.ts
  • packages/3-targets/3-targets/postgres/src/exports/codecs.ts
  • packages/3-targets/3-targets/postgres/test/codec-render-output-type.test.ts
  • packages/3-targets/3-targets/postgres/test/codecs-class.test.ts
  • packages/3-targets/3-targets/postgres/test/codecs-class.types.test-d.ts
  • packages/3-targets/3-targets/postgres/test/codecs.test.ts
  • packages/3-targets/3-targets/postgres/test/typed-descriptor-flow.test-d.ts
  • packages/3-targets/3-targets/sqlite/src/core/codecs-class.ts
  • packages/3-targets/3-targets/sqlite/src/core/registry.ts
  • packages/3-targets/3-targets/sqlite/src/exports/codec-types.ts
  • packages/3-targets/3-targets/sqlite/src/exports/codecs.ts
  • packages/3-targets/3-targets/sqlite/test/codecs-class.types.test-d.ts
  • packages/3-targets/3-targets/sqlite/test/typed-descriptor-flow.test-d.ts
  • packages/3-targets/6-adapters/postgres/src/core/adapter.ts
  • packages/3-targets/6-adapters/postgres/src/core/codec-lookup.ts
  • packages/3-targets/6-adapters/postgres/src/core/descriptor-meta.ts
  • packages/3-targets/6-adapters/postgres/src/exports/runtime.ts
  • packages/3-targets/6-adapters/sqlite/src/core/adapter.ts
  • packages/3-targets/6-adapters/sqlite/src/core/runtime-adapter.ts
  • packages/3-targets/6-adapters/sqlite/test/codecs.test.ts
✅ Files skipped from review due to trivial changes (9)
  • packages/2-sql/4-lanes/relational-core/package.json
  • packages/2-sql/4-lanes/relational-core/src/exports/codec-descriptor-registry.ts
  • packages/3-targets/3-targets/postgres/src/core/registry.ts
  • packages/3-extensions/pgvector/src/core/registry.ts
  • packages/3-targets/3-targets/sqlite/src/core/registry.ts
  • packages/2-sql/4-lanes/relational-core/tsdown.config.ts
  • packages/3-extensions/arktype-json/src/exports/codecs.ts
  • packages/3-extensions/arktype-json/src/core/pack-meta.ts
  • packages/3-targets/3-targets/sqlite/src/exports/codecs.ts
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/3-targets/3-targets/postgres/src/exports/codecs.ts
  • packages/3-targets/3-targets/postgres/test/codecs-class.types.test-d.ts
  • packages/2-sql/5-runtime/src/sql-context.ts
  • packages/3-targets/3-targets/postgres/src/core/codecs-class.ts

Comment thread packages/3-extensions/pgvector/src/core/codecs.ts Outdated
Comment thread packages/3-targets/3-targets/postgres/src/exports/codec-types.ts Outdated
Comment thread packages/3-targets/3-targets/sqlite/src/core/codecs-class.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/3-targets/3-targets/postgres/src/core/codecs.ts (1)

110-124: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

The length-parameter helpers can emit params their descriptors reject.

lengthParamsSchema requires length, but LengthParams is optional and these helpers default to {}. That means pgBitColumn(), pgVarbitColumn(), pgCharColumn(), and pgVarcharColumn() can author column specs that fail descriptor validation later.

Either make length required at the helper boundary, or relax the relevant schemas if bare forms are intentionally supported. Right now the API surface and validator contract disagree.

Also applies to: 733-735, 779-780, 1008-1035

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/3-targets/3-targets/postgres/src/core/codecs.ts` around lines 110 -
124, The helper functions (e.g., pgBitColumn, pgVarbitColumn, pgCharColumn,
pgVarcharColumn) are producing param objects that the validator
lengthParamsSchema rejects because lengthParamsSchema requires length while the
Type LengthParams and helpers allow an empty {}; fix by reconciling the
contract: either relax lengthParamsSchema to accept an optional length (change
length to 'number.integer > 0' -> 'number.integer > 0?') so bare forms validate,
or make the helpers enforce/require length at their boundary (update the helper
implementations to validate and throw or return an error when length is missing)
and change LengthParams to require length; apply the same reconciliation for the
related numeric/precision schemas and their helper functions referenced in the
comment (numericParamsSchema, precisionParamsSchema and their callers).
♻️ Duplicate comments (3)
packages/3-extensions/pgvector/src/core/codecs.ts (1)

76-118: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Carry length into PgVectorCodec and validate every ingress path.

factory() still materializes the same codec for vector(3) and vector(1536), and decodeJson() still force-casts JSON to number[]. That means wrong-dimension or non-numeric vectors can get past the codec boundary until much later.

Suggested direction
 export class PgVectorCodec extends CodecImpl<
   typeof VECTOR_CODEC_ID,
   readonly ['equality'],
   string,
   number[]
 > {
+  constructor(
+    descriptor: PgVectorDescriptor,
+    private readonly length: number,
+  ) {
+    super(descriptor);
+  }
+
+  private assertVector(value: JsonValue | number[]): asserts value is number[] {
+    if (!Array.isArray(value)) {
+      throw new Error('Vector value must be an array of numbers');
+    }
+    if (!value.every((v) => typeof v === 'number')) {
+      throw new Error('Vector value must contain only numbers');
+    }
+    if (value.length !== this.length) {
+      throw new Error(`Vector length mismatch: expected ${this.length}, got ${value.length}`);
+    }
+  }
+
   async encode(value: number[], _ctx: CodecCallContext): Promise<string> {
-    if (!Array.isArray(value)) {
-      throw new Error('Vector value must be an array of numbers');
-    }
-    if (!value.every((v) => typeof v === 'number')) {
-      throw new Error('Vector value must contain only numbers');
-    }
+    this.assertVector(value);
     return `[${value.join(',')}]`;
   }

   async decode(wire: string, _ctx: CodecCallContext): Promise<number[]> {
@@
-    return content.split(',').map((v) => {
+    const value = content.split(',').map((v) => {
       const num = Number.parseFloat(v.trim());
       if (Number.isNaN(num)) {
         throw new Error(`Invalid vector value: "${v}" is not a number`);
       }
       return num;
     });
+    this.assertVector(value);
+    return value;
   }

   encodeJson(value: number[]): JsonValue {
+    this.assertVector(value);
     return value;
   }

   decodeJson(json: JsonValue): number[] {
-    return json as number[];
+    this.assertVector(json);
+    return json;
   }
 }
@@
-  override factory(_params: VectorParams): (ctx: CodecInstanceContext) => PgVectorCodec {
-    return () => new PgVectorCodec(this);
+  override factory(params: VectorParams): (ctx: CodecInstanceContext) => PgVectorCodec {
+    return () => new PgVectorCodec(this, params.length);
   }
 }

Also applies to: 130-132

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/3-extensions/pgvector/src/core/codecs.ts` around lines 76 - 118,
PgVectorCodec currently ignores the declared vector dimension so invalid-length
or non-numeric vectors slip through; modify the factory() that constructs
PgVectorCodec to accept and store the vector length into the codec instance,
then validate that length in all ingress/egress paths: in encode(value), ensure
value is an array of numbers of the expected length; in decode(wire) after
parsing, ensure the resulting number[] has the expected length; in
encodeJson(value) validate the array contents and length before returning; in
decodeJson(json) validate that json is an array of numbers and the correct
length (don’t force-cast). Update the PgVectorCodec class signature to carry a
length field and use it in these methods to throw descriptive errors on mismatch
or non-numeric entries.
packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs-class.ts (1)

67-76: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Make the char/varchar helper contract match the descriptor schema.

Lines 75-76, 245-246, and 290-291 make length optional and default helper params to {}, but lengthParamsSchema on Lines 67-69 still requires it. That lets sqlCharColumn() / sqlVarcharColumn() produce type params that their own descriptors later reject.

One fix if bare forms are not intended
-type LengthParams = { readonly length?: number };
+type LengthParams = { readonly length: number };
@@
-export const sqlCharColumn = (params: LengthParams = {}) =>
+export const sqlCharColumn = (params: LengthParams) =>
   column(sqlCharDescriptor.factory(params), sqlCharDescriptor.codecId, params, 'char');
@@
-export const sqlVarcharColumn = (params: LengthParams = {}) =>
+export const sqlVarcharColumn = (params: LengthParams) =>
   column(sqlVarcharDescriptor.factory(params), sqlVarcharDescriptor.codecId, params, 'varchar');

If bare char / varchar is intentional, relax lengthParamsSchema instead so validation matches the helper API.

Also applies to: 245-246, 290-291

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs-class.ts` around
lines 67 - 76, The length validation in lengthParamsSchema conflicts with the
helper defaults used by sqlCharColumn and sqlVarcharColumn—lengthParamsSchema
currently requires length but the helpers make length optional and default to
{}—so relax the schema to allow an optional length (e.g. change the key to
'length?' with the same numeric constraint) so the descriptor validation matches
the helper API; alternatively, if you intend bare forms to be disallowed, make
sqlCharColumn/sqlVarcharColumn require and pass a length instead, but the
simpler fix is to update lengthParamsSchema to accept an optional length to
align with LengthParams and the helpers.
packages/3-extensions/arktype-json/test/arktype-json-codec.test.ts (1)

74-77: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Drop the any cast and Biome suppression in this negative-path test.

This still violates the repo’s test rules. A single @ts-expect-error on Line 77 keeps the runtime-guard coverage without suppressing lint or widening to any.

Suggested cleanup
   it('rejects non-callable schema lookalikes at the call site', () => {
     const notASchema = { foo: 'bar' };
-    // biome-ignore lint/suspicious/noExplicitAny: deliberately malformed input for the call-site guard
-    expect(() => arktypeJsonColumn(notASchema as any)).toThrow(/callable arktype Type/);
+    // `@ts-expect-error` -- intentionally passing a non-callable to exercise the runtime guard
+    expect(() => arktypeJsonColumn(notASchema)).toThrow(/callable arktype Type/);
   });

As per coding guidelines, "Never use any type", "Never suppress biome lints", and "Use @ts-expect-error with a short reason in tests instead of blanket @ts-ignore."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/3-extensions/arktype-json/test/arktype-json-codec.test.ts` around
lines 74 - 77, The test currently uses an any cast and a biome-ignore to pass a
malformed value into arktypeJsonColumn (variable notASchema) which violates
project rules; remove the "as any" cast and the biome-ignore comment and instead
put a single line with `@ts-expect-error` and a short reason immediately above the
expect(() => arktypeJsonColumn(notASchema)).toThrow(...) call so the TypeScript
compile-time error is expected while preserving the runtime negative-path
assertion for arktypeJsonColumn.
🧹 Nitpick comments (2)
packages/3-targets/3-targets/sqlite/src/exports/codec-types.ts (1)

11-45: ⚡ Quick win

Keep src/exports/codec-types.ts as a pure re-export surface.

This entrypoint now computes codecDescriptorMap, Resolve, and CodecTypes inline. That breaks the repo’s src/exports/* rule; move the implementation into a core module and re-export the finished type from here.

♻️ Suggested shape
-import type { ExtractCodecTypes } from '@prisma-next/sql-relational-core/ast';
-import {
-  sqlCharDescriptor,
-  sqlFloatDescriptor,
-  sqlIntDescriptor,
-  sqlVarcharDescriptor,
-} from '@prisma-next/sql-relational-core/ast';
 import type { JsonValue } from '../core/codec-helpers';
-import {
-  sqliteBigintDescriptor,
-  sqliteBlobDescriptor,
-  sqliteDatetimeDescriptor,
-  sqliteIntegerDescriptor,
-  sqliteJsonDescriptor,
-  sqliteRealDescriptor,
-  sqliteTextDescriptor,
-} from '../core/codecs';
-
-const codecDescriptorMap = {
-  char: sqlCharDescriptor,
-  varchar: sqlVarcharDescriptor,
-  int: sqlIntDescriptor,
-  float: sqlFloatDescriptor,
-  text: sqliteTextDescriptor,
-  integer: sqliteIntegerDescriptor,
-  real: sqliteRealDescriptor,
-  blob: sqliteBlobDescriptor,
-  datetime: sqliteDatetimeDescriptor,
-  json: sqliteJsonDescriptor,
-  bigint: sqliteBigintDescriptor,
-} as const;
-
-type Resolve<T> = { readonly [K in keyof T]: { readonly [P in keyof T[K]]: T[K][P] } };
-
-export type CodecTypes = Resolve<ExtractCodecTypes<typeof codecDescriptorMap>>;
+export type { CodecTypes } from '../core/codec-types';

As per coding guidelines, "Re-export files in src/exports/ (adapter.ts, codec-types.ts, types.ts) must re-export from core (../core/...) without adding additional logic."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/3-targets/3-targets/sqlite/src/exports/codec-types.ts` around lines
11 - 45, The file currently computes codecDescriptorMap, Resolve and CodecTypes
inline; move that logic into a new core module (e.g. ../core/codec-types.ts)
where you export the const codecDescriptorMap, the helper Resolve type and the
resulting export type CodecTypes (using ExtractCodecTypes and the existing codec
descriptors like sqliteTextDescriptor, sqliteIntegerDescriptor, etc.), then
change this src/exports/codec-types.ts to be a pure re-export that only
re-exports the finished type (e.g. export type { CodecTypes } from
'../core/codec-types';) and any needed descriptor re-exports—remove all inline
computation from the exports file.
packages/2-sql/4-lanes/relational-core/src/ast/codec-types.ts (1)

238-248: 💤 Low value

Both input and output correctly use DescriptorCodecInput — no issue found.

The current implementation is semantically correct. Both input and output represent the application-facing type (TInput) per codec contract semantics: codecs encode application values to wire format and decode wire format back to application values. Tests confirm this: ContractCodecTypes['pg/int4@1']['output'] correctly infers number.

The naming could benefit from a brief inline comment clarifying that input and output both refer to the application-side type (as opposed to wire format), but this is a minor optional clarity improvement, not a functional issue.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/2-sql/4-lanes/relational-core/src/ast/codec-types.ts` around lines
238 - 248, Add a brief inline comment in the ExtractCodecTypes type to clarify
that both properties named input and output use DescriptorCodecInput and
therefore represent the application-facing type (TInput) rather than the wire
format; update the area around the ExtractCodecTypes declaration (reference the
type name ExtractCodecTypes and the properties input/output that use
DescriptorCodecInput and DescriptorCodecTraits) to include a one-line comment
explaining this semantic choice for future readers.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/3-targets/3-targets/postgres/src/core/codec-helpers.ts`:
- Around line 55-72: The pgNumericRenderOutputType function currently allows any
JS number for typeParams.scale (including NaN/Infinity/floats) which can produce
invalid output like "Numeric<10, NaN>"; update pgNumericRenderOutputType to
validate typeParams.scale the same way precision is validated: check typeof
scale === 'number', Number.isFinite(scale), and Number.isInteger(scale) (and
throw a similar Error mentioning "scale" when invalid), and only render
`Numeric<precision, scale>` when the validated scale is present; otherwise fall
back to `Numeric<precision>`.
- Around line 103-114: The function pgEnumRenderOutputType currently coerces all
enum values with String(value); instead, validate that typeParams.values is an
array of strings and throw a descriptive Error if any element is not a string
before rendering. In pgEnumRenderOutputType inspect values (e.g. values.forEach
or values.some) and if an element's typeof !== 'string' throw an Error naming
the offending index/type (or a clear message) so only string literals are
processed, then proceed to escape and join the strings as before.
- Around line 75-96: Both pgTimestampDecodeJson and pgTimestamptzDecodeJson
currently accept any format the Date constructor parses; change them to first
validate the input string against a strict ISO 8601 regex (e.g., RFC3339-like
pattern) before constructing a Date, and remove the round-trip toISOString()
equality check (use the regex + Number.isNaN(date.getTime()) checks only) so
inputs like "2024-01-15T10:30:00Z" are accepted while non-ISO inputs are
rejected; update the error messages in pgTimestampDecodeJson and
pgTimestamptzDecodeJson to reflect the ISO-only requirement.

In `@packages/3-targets/3-targets/sqlite/src/core/codecs.ts`:
- Around line 245-259: The decode methods currently create Date objects from
strings but don't validate them, allowing invalid Dates to propagate; update
both decode(wire: string) and decodeJson(json: JsonValue) to parse the string
into a Date (using new Date(...)) and then check validity with
isNaN(date.getTime()) (or Number.isNaN(date.getTime())); if invalid, throw a
TypeError with the same contract message used now ('sqlite/datetime@1 contract
value must be an ISO-8601 string'); otherwise return the valid Date. Apply this
change to the decode and decodeJson functions to reject malformed datetime
strings early.

---

Outside diff comments:
In `@packages/3-targets/3-targets/postgres/src/core/codecs.ts`:
- Around line 110-124: The helper functions (e.g., pgBitColumn, pgVarbitColumn,
pgCharColumn, pgVarcharColumn) are producing param objects that the validator
lengthParamsSchema rejects because lengthParamsSchema requires length while the
Type LengthParams and helpers allow an empty {}; fix by reconciling the
contract: either relax lengthParamsSchema to accept an optional length (change
length to 'number.integer > 0' -> 'number.integer > 0?') so bare forms validate,
or make the helpers enforce/require length at their boundary (update the helper
implementations to validate and throw or return an error when length is missing)
and change LengthParams to require length; apply the same reconciliation for the
related numeric/precision schemas and their helper functions referenced in the
comment (numericParamsSchema, precisionParamsSchema and their callers).

---

Duplicate comments:
In `@packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs-class.ts`:
- Around line 67-76: The length validation in lengthParamsSchema conflicts with
the helper defaults used by sqlCharColumn and
sqlVarcharColumn—lengthParamsSchema currently requires length but the helpers
make length optional and default to {}—so relax the schema to allow an optional
length (e.g. change the key to 'length?' with the same numeric constraint) so
the descriptor validation matches the helper API; alternatively, if you intend
bare forms to be disallowed, make sqlCharColumn/sqlVarcharColumn require and
pass a length instead, but the simpler fix is to update lengthParamsSchema to
accept an optional length to align with LengthParams and the helpers.

In `@packages/3-extensions/arktype-json/test/arktype-json-codec.test.ts`:
- Around line 74-77: The test currently uses an any cast and a biome-ignore to
pass a malformed value into arktypeJsonColumn (variable notASchema) which
violates project rules; remove the "as any" cast and the biome-ignore comment
and instead put a single line with `@ts-expect-error` and a short reason
immediately above the expect(() => arktypeJsonColumn(notASchema)).toThrow(...)
call so the TypeScript compile-time error is expected while preserving the
runtime negative-path assertion for arktypeJsonColumn.

In `@packages/3-extensions/pgvector/src/core/codecs.ts`:
- Around line 76-118: PgVectorCodec currently ignores the declared vector
dimension so invalid-length or non-numeric vectors slip through; modify the
factory() that constructs PgVectorCodec to accept and store the vector length
into the codec instance, then validate that length in all ingress/egress paths:
in encode(value), ensure value is an array of numbers of the expected length; in
decode(wire) after parsing, ensure the resulting number[] has the expected
length; in encodeJson(value) validate the array contents and length before
returning; in decodeJson(json) validate that json is an array of numbers and the
correct length (don’t force-cast). Update the PgVectorCodec class signature to
carry a length field and use it in these methods to throw descriptive errors on
mismatch or non-numeric entries.

---

Nitpick comments:
In `@packages/2-sql/4-lanes/relational-core/src/ast/codec-types.ts`:
- Around line 238-248: Add a brief inline comment in the ExtractCodecTypes type
to clarify that both properties named input and output use DescriptorCodecInput
and therefore represent the application-facing type (TInput) rather than the
wire format; update the area around the ExtractCodecTypes declaration (reference
the type name ExtractCodecTypes and the properties input/output that use
DescriptorCodecInput and DescriptorCodecTraits) to include a one-line comment
explaining this semantic choice for future readers.

In `@packages/3-targets/3-targets/sqlite/src/exports/codec-types.ts`:
- Around line 11-45: The file currently computes codecDescriptorMap, Resolve and
CodecTypes inline; move that logic into a new core module (e.g.
../core/codec-types.ts) where you export the const codecDescriptorMap, the
helper Resolve type and the resulting export type CodecTypes (using
ExtractCodecTypes and the existing codec descriptors like sqliteTextDescriptor,
sqliteIntegerDescriptor, etc.), then change this src/exports/codec-types.ts to
be a pure re-export that only re-exports the finished type (e.g. export type {
CodecTypes } from '../core/codec-types';) and any needed descriptor
re-exports—remove all inline computation from the exports file.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 9bcd7dd3-79d5-45a7-9aef-23e5489f668f

📥 Commits

Reviewing files that changed from the base of the PR and between 583a8e9 and c4d81ad.

📒 Files selected for processing (42)
  • docs/reference/codec-authoring-guide.md
  • packages/2-sql/4-lanes/relational-core/README.md
  • packages/2-sql/4-lanes/relational-core/src/ast/codec-types.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs-class.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codecs-class.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/typed-codec-flow.test-d.ts
  • packages/2-sql/5-runtime/src/sql-context.ts
  • packages/3-extensions/arktype-json/src/core/arktype-json-codec.ts
  • packages/3-extensions/arktype-json/src/core/pack-meta.ts
  • packages/3-extensions/arktype-json/src/core/registry.ts
  • packages/3-extensions/arktype-json/src/exports/codecs.ts
  • packages/3-extensions/arktype-json/src/exports/column-types.ts
  • packages/3-extensions/arktype-json/src/exports/runtime.ts
  • packages/3-extensions/arktype-json/test/arktype-json-codec.test.ts
  • packages/3-extensions/arktype-json/test/arktype-json-codec.types.test-d.ts
  • packages/3-extensions/arktype-json/test/extension-descriptors.test.ts
  • packages/3-extensions/pgvector/src/core/codecs.ts
  • packages/3-extensions/pgvector/src/core/registry.ts
  • packages/3-extensions/pgvector/test/codec-render-output-type.test.ts
  • packages/3-extensions/pgvector/test/codecs-class.types.test-d.ts
  • packages/3-extensions/pgvector/test/codecs.test.ts
  • packages/3-extensions/pgvector/test/typed-descriptor-flow.test-d.ts
  • packages/3-extensions/sql-orm-client/test/codec-async.types.test-d.ts
  • packages/3-extensions/sql-orm-client/test/integration/codec-async.test.ts
  • packages/3-targets/3-targets/postgres/src/core/codec-helpers.ts
  • packages/3-targets/3-targets/postgres/src/core/codecs.ts
  • packages/3-targets/3-targets/postgres/src/core/registry.ts
  • packages/3-targets/3-targets/postgres/src/exports/codec-types.ts
  • packages/3-targets/3-targets/postgres/src/exports/codecs.ts
  • packages/3-targets/3-targets/postgres/test/codec-render-output-type.test.ts
  • packages/3-targets/3-targets/postgres/test/codecs-class.test.ts
  • packages/3-targets/3-targets/postgres/test/codecs-class.types.test-d.ts
  • packages/3-targets/3-targets/postgres/test/codecs.test.ts
  • packages/3-targets/3-targets/postgres/test/typed-descriptor-flow.test-d.ts
  • packages/3-targets/3-targets/sqlite/src/core/codec-helpers.ts
  • packages/3-targets/3-targets/sqlite/src/core/codecs.ts
  • packages/3-targets/3-targets/sqlite/src/core/registry.ts
  • packages/3-targets/3-targets/sqlite/src/exports/codec-types.ts
  • packages/3-targets/3-targets/sqlite/src/exports/codecs.ts
  • packages/3-targets/3-targets/sqlite/test/codecs-class.types.test-d.ts
  • packages/3-targets/3-targets/sqlite/test/typed-descriptor-flow.test-d.ts
✅ Files skipped from review due to trivial changes (16)
  • packages/3-targets/3-targets/postgres/src/core/registry.ts
  • packages/3-extensions/pgvector/src/core/registry.ts
  • packages/3-extensions/sql-orm-client/test/integration/codec-async.test.ts
  • packages/3-extensions/sql-orm-client/test/codec-async.types.test-d.ts
  • packages/3-targets/3-targets/sqlite/src/core/registry.ts
  • packages/3-targets/3-targets/postgres/src/exports/codecs.ts
  • packages/3-extensions/pgvector/test/codec-render-output-type.test.ts
  • packages/3-extensions/arktype-json/src/core/registry.ts
  • packages/3-extensions/pgvector/test/typed-descriptor-flow.test-d.ts
  • packages/3-extensions/arktype-json/src/exports/codecs.ts
  • packages/2-sql/4-lanes/relational-core/README.md
  • packages/3-targets/3-targets/postgres/test/codecs-class.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/typed-codec-flow.test-d.ts
  • docs/reference/codec-authoring-guide.md
  • packages/2-sql/5-runtime/src/sql-context.ts
  • packages/3-targets/3-targets/postgres/src/exports/codec-types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/3-extensions/arktype-json/src/exports/column-types.ts

Comment thread packages/3-targets/3-targets/postgres/src/core/codec-helpers.ts
Comment thread packages/3-targets/3-targets/postgres/src/core/codec-helpers.ts
Comment thread packages/3-targets/3-targets/postgres/src/core/codec-helpers.ts
Comment thread packages/3-targets/3-targets/sqlite/src/core/codecs.ts
Comment thread packages/1-framework/1-core/framework-components/src/control/control-stack.ts Outdated
Comment thread packages/1-framework/0-foundation/contract/src/standard-schema-utils.ts Outdated
Comment thread packages/1-framework/1-core/framework-components/src/control/control-stack.ts Outdated
Comment thread packages/1-framework/1-core/framework-components/test/control-stack.test.ts Outdated
Comment thread packages/3-targets/3-targets/postgres/src/core/codecs-class.ts Outdated
Comment thread packages/3-targets/3-targets/postgres/src/core/codecs-class.ts Outdated
Comment thread packages/1-framework/0-foundation/contract/src/standard-schema-utils.ts Outdated
Comment thread packages/1-framework/1-core/framework-components/src/control/control-stack.ts Outdated
Comment thread packages/1-framework/1-core/framework-components/src/shared/codec.ts Outdated
Comment thread packages/2-sql/4-lanes/relational-core/src/ast/codec-types.ts Outdated
Comment thread packages/2-sql/4-lanes/relational-core/src/ast/validate-param-refs.ts Outdated
@wmadden
Copy link
Copy Markdown
Contributor Author

wmadden commented May 8, 2026

All actionable items in this review body are addressed in the inline thread replies; see those for closing commits.

On the outside-diff finding for packages/2-sql/5-runtime/src/sql-context.ts:493-516 (collapsing non-parameterized column codecs to one instance per codecId): this is the documented F27 phase 2 design (commit 0e3aafc0b). Non-parameterized codecs are, by definition, independent of column context — the name / usedAt from CodecInstanceContext is metadata for diagnostics, not state the conversion logic is allowed to depend on. Column-aware dispatch is reserved for parameterized codecs and flows through forColumn (F22+F26+F29 cluster, commit 20f99bffd); the cluster also adds ambiguousCodecIds rejection so a parameterized codec cannot accidentally collapse via this byCodecId path.

The nitpicks (column-spec generic threading, Object.hasOwn on the test fixture, barrel imports in relational-core/test/utils.ts, the unreachable precision === undefined check) are noted but out of scope for TML-2357 — they're cleanup follow-ups that don't affect this PR's acceptance criteria. Closing.

@wmadden
Copy link
Copy Markdown
Contributor Author

wmadden commented May 8, 2026

All actionable findings in this review body are duplicates of inline threads or other review bodies and are closed:

  • arktype-json-codec-class.ts rehydrateSchema double-cast → F23 (48ed1d135): replaced with isArktypeSchemaLike type-predicate; rehydration throws RUNTIME.JSON_SCHEMA_VALIDATION_FAILED on shape mismatch.
  • arktype-json-codec-class.test.ts as any + biome-ignore → F24 (48ed1d135): replaced with @ts-expect-error.
  • arktype-json-codec-class.types.test-d.ts deprecated toMatchTypeOf → F25 (48ed1d135): replaced with toExtend.
  • sqlite/codecs-class.ts:245-258 invalid Date → F37 (182d10c88): shared parseDate helper.
  • sql-codecs-class.ts:67-76 lengthParamsSchema vs LengthParams mismatch → F20 (cfa078a23): schema tightened to 'length?': 'number.integer > 0'; helpers' params: LengthParams = {} now agrees end-to-end.

Nitpicks (nudges on adapter.ts factory(undefined) invariants and the codecs.test.ts paramsByScalar shape) are noted but out of scope for TML-2357. Closing.

@wmadden
Copy link
Copy Markdown
Contributor Author

wmadden commented May 8, 2026

All actionable findings in this review body are closed via the inline thread replies (F29, F34, F35, F36, F37, F39 — see those threads for closing commits).

On the outside-diff finding for packages/3-targets/3-targets/postgres/src/core/codecs.ts:110-124 (length-parameter helpers emitting params their descriptors reject): closed by the F20 closure (commit cfa078a23) that tightened lengthParamsSchema to 'length?': 'number.integer > 0' so the schema and the helpers' params: LengthParams = {} agree, and by F11 (f725db1f8) which split the SQL helpers cleanly.

Nitpicks (descriptor-first shape for codecs.test.ts:75-82, runtime-neutral base64 for sqlite/codecs-class.ts:204-211, fail-fast factory(undefined) invariant in postgres/sqlite adapters) are noted but out of scope for TML-2357. Closing.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/2-sql/5-runtime/src/codecs/encoding.ts (1)

141-144: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve codec-authored runtime errors during encode.

encodeParamValue() wraps every thrown error as RUNTIME.ENCODE_FAILED. That double-wraps codec-generated RUNTIME.ENCODE_FAILED envelopes and downgrades a codec-thrown RUNTIME.ABORTED into the wrong error code. Pass known runtime envelopes through before calling wrapEncodeFailure().

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/2-sql/5-runtime/src/codecs/encoding.ts` around lines 141 - 144, In
encodeParamValue's catch block around codec.encode(value, ctx), detect if the
thrown error is already a runtime envelope (i.e., a codec-authored runtime
error/exception) and rethrow it unchanged instead of wrapping; otherwise call
wrapEncodeFailure(error, metadata, paramIndex, codec.id). Update the catch to
explicitly pass through known runtime envelopes (identify by the runtime
envelope shape/marker used in this project) before invoking wrapEncodeFailure so
codec-thrown RUNTIME.* errors are preserved.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/2-sql/5-runtime/src/codecs/decoding.ts`:
- Around line 260-263: decodeField currently wraps every thrown error into
RUNTIME.DECODE_FAILED; change the catch in decodeField so it only calls
wrapDecodeFailure for non-runtime/foreign errors: if the caught error is already
a codec-produced runtime envelope (e.g., has the runtime failure shape or codes
like RUNTIME.DECODE_FAILED or RUNTIME.ABORTED) then rethrow it unchanged,
otherwise call wrapDecodeFailure(alias, ref, codec, wireValue) and throw that;
reference the decodeField function, the codec.decode call, and wrapDecodeFailure
when making this conditional check so codec-authored runtime envelopes are
preserved.

In `@packages/2-sql/5-runtime/src/sql-context.ts`:
- Around line 273-282: The partitioning logic currently checks
descriptor.paramsSchema !== voidParamsSchema which is brittle; change the branch
to use the descriptor.isParameterized boolean as the discriminator so
descriptors are routed correctly into the parameterized map
(parameterized.set(... as RuntimeParameterizedCodecDescriptor)) vs the
unparameterized path, ensuring validateTypeParams() and initializeTypeHelpers()
are invoked for parameterized descriptors; update any comments referencing
paramsSchema identity to reflect isParameterized as the source of truth.
- Around line 410-427: The current loop pre-creates and caches a single shared
codec instance in byCodecId and then reuses that same instance for column-bound
lookups, causing descriptor.factory to see the shared SqlCodecInstanceContext
instead of the real column context; change the logic so the pre-populated
instance remains only as the forCodecId() fallback, and when populating entries
for forColumn(table, column) always materialize a fresh codec instance via
descriptor.factory(...) with a column-specific SqlCodecInstanceContext (e.g.
name like `<col:${table}.${column}>` and usedAt set to the column site) rather
than reusing the shared instance; apply the same change in the second block
referenced (the code around the 492-512 region) so non-parameterized descriptors
are only cached as a fallback and per-column instances are created with real
column contexts.

In `@packages/3-mongo-target/2-mongo-adapter/src/core/codecs.ts`:
- Around line 121-124: The guard in renderOutputType that validates the variable
length currently only checks for number, finiteness, and integer-ness but allows
0 and negatives; update the validation in renderOutputType (in codecs.ts) to
also require length > 0 and throw the same (or a clearer) Error when length is
not a positive integer so invalid inputs cannot produce Vector<0> or Vector<-1>.

---

Outside diff comments:
In `@packages/2-sql/5-runtime/src/codecs/encoding.ts`:
- Around line 141-144: In encodeParamValue's catch block around
codec.encode(value, ctx), detect if the thrown error is already a runtime
envelope (i.e., a codec-authored runtime error/exception) and rethrow it
unchanged instead of wrapping; otherwise call wrapEncodeFailure(error, metadata,
paramIndex, codec.id). Update the catch to explicitly pass through known runtime
envelopes (identify by the runtime envelope shape/marker used in this project)
before invoking wrapEncodeFailure so codec-thrown RUNTIME.* errors are
preserved.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: bd164814-d8cb-4c7c-9ca5-571e8aa245a4

📥 Commits

Reviewing files that changed from the base of the PR and between c4d81ad and 0e3aafc.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (61)
  • docs/reference/codec-authoring-guide.md
  • examples/prisma-next-demo/test/no-emit-typed-flow.test-d.ts
  • packages/1-framework/1-core/framework-components/src/control/control-stack.ts
  • packages/1-framework/1-core/framework-components/src/shared/codec-descriptor.ts
  • packages/1-framework/1-core/framework-components/src/shared/codec.ts
  • packages/1-framework/1-core/framework-components/test/codec-types.types.test-d.ts
  • packages/1-framework/1-core/framework-components/test/control-stack.test.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/adapter-types.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/codec-types.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/sql-codec-helpers.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/validate-param-refs.ts
  • packages/2-sql/4-lanes/relational-core/src/codec-descriptor-registry.ts
  • packages/2-sql/4-lanes/relational-core/src/exports/ast.ts
  • packages/2-sql/4-lanes/relational-core/src/query-lane-context.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codec-helpers.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codecs.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codecs.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/validate-param-refs.test.ts
  • packages/2-sql/4-lanes/relational-core/test/typed-codec-flow.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/utils.ts
  • packages/2-sql/5-runtime/src/codecs/decoding.ts
  • packages/2-sql/5-runtime/src/codecs/encoding.ts
  • packages/2-sql/5-runtime/src/codecs/validation.ts
  • packages/2-sql/5-runtime/src/sql-context.ts
  • packages/2-sql/5-runtime/src/sql-runtime.ts
  • packages/2-sql/5-runtime/test/before-compile-chain.test.ts
  • packages/2-sql/5-runtime/test/codec-async.test.ts
  • packages/2-sql/5-runtime/test/codec-decode-ctx.test.ts
  • packages/2-sql/5-runtime/test/codec-encode-ctx.test.ts
  • packages/2-sql/5-runtime/test/contract-codec-registry.test.ts
  • packages/2-sql/5-runtime/test/encoding-dispatch.test.ts
  • packages/2-sql/5-runtime/test/execution-stack.test.ts
  • packages/2-sql/5-runtime/test/parameterized-types.test.ts
  • packages/2-sql/5-runtime/test/sql-context.test.ts
  • packages/2-sql/5-runtime/test/sql-family-adapter.test.ts
  • packages/2-sql/5-runtime/test/sql-runtime-abort.test.ts
  • packages/2-sql/5-runtime/test/sql-runtime.test.ts
  • packages/2-sql/5-runtime/test/utils.ts
  • packages/3-extensions/arktype-json/package.json
  • packages/3-extensions/arktype-json/src/core/arktype-json-codec.ts
  • packages/3-extensions/arktype-json/test/arktype-json-codec.test.ts
  • packages/3-extensions/arktype-json/test/arktype-json-codec.types.test-d.ts
  • packages/3-extensions/pgvector/package.json
  • packages/3-extensions/pgvector/src/core/codecs.ts
  • packages/3-extensions/pgvector/test/codecs.test.ts
  • packages/3-extensions/sql-orm-client/src/types.ts
  • packages/3-extensions/sql-orm-client/test/model-accessor.test.ts
  • packages/3-mongo-target/2-mongo-adapter/src/core/codecs.ts
  • packages/3-targets/3-targets/postgres/src/core/codec-helpers.ts
  • packages/3-targets/3-targets/postgres/src/core/codec-type-map.ts
  • packages/3-targets/3-targets/postgres/src/core/codecs.ts
  • packages/3-targets/3-targets/postgres/src/exports/codec-types.ts
  • packages/3-targets/3-targets/postgres/test/codecs-class.types.test-d.ts
  • packages/3-targets/3-targets/sqlite/src/core/codecs.ts
  • packages/3-targets/6-adapters/postgres/src/core/adapter.ts
  • packages/3-targets/6-adapters/postgres/test/adapter.test.ts
  • packages/3-targets/6-adapters/postgres/test/descriptor-parity.test.ts
  • packages/3-targets/6-adapters/postgres/test/sql-renderer.cast-policy.test.ts
  • packages/3-targets/6-adapters/sqlite/src/core/adapter.ts
  • test/integration/test/cross-package/cross-family-codec.test.ts
💤 Files with no reviewable changes (2)
  • packages/2-sql/4-lanes/relational-core/src/ast/adapter-types.ts
  • packages/2-sql/5-runtime/test/sql-family-adapter.test.ts
✅ Files skipped from review due to trivial changes (2)
  • packages/3-extensions/arktype-json/package.json
  • packages/3-extensions/arktype-json/test/arktype-json-codec.types.test-d.ts
🚧 Files skipped from review as they are similar to previous changes (16)
  • packages/2-sql/5-runtime/test/codec-async.test.ts
  • packages/1-framework/1-core/framework-components/src/shared/codec-descriptor.ts
  • packages/3-targets/3-targets/postgres/test/codecs-class.types.test-d.ts
  • packages/1-framework/1-core/framework-components/test/control-stack.test.ts
  • packages/1-framework/1-core/framework-components/test/codec-types.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/src/codec-descriptor-registry.ts
  • packages/1-framework/1-core/framework-components/src/control/control-stack.ts
  • packages/2-sql/5-runtime/test/contract-codec-registry.test.ts
  • examples/prisma-next-demo/test/no-emit-typed-flow.test-d.ts
  • packages/2-sql/5-runtime/test/execution-stack.test.ts
  • packages/2-sql/5-runtime/test/encoding-dispatch.test.ts
  • packages/3-extensions/pgvector/src/core/codecs.ts
  • packages/2-sql/4-lanes/relational-core/test/typed-codec-flow.test-d.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs.ts
  • packages/3-targets/3-targets/postgres/src/core/codec-helpers.ts
  • packages/3-targets/3-targets/postgres/src/core/codecs.ts

Comment thread packages/2-sql/5-runtime/src/codecs/decoding.ts
Comment thread packages/2-sql/5-runtime/src/sql-context.ts Outdated
Comment thread packages/2-sql/5-runtime/src/sql-context.ts
Comment thread packages/3-mongo-target/2-mongo-adapter/src/core/codecs.ts Outdated
wmadden and others added 16 commits May 9, 2026 07:40
Completes the registration-side migration codec-registry-unification
(TML-2229) deferred. Branched off origin/main post-TML-2229 merge.

Six structural defects in the codec registration model retire across
four milestones:

- M1: narrow runtime Codec instance to `{ id, encode, decode, encodeJson,
  decodeJson }`; route emit-path renderOutputType through
  descriptorFor(codecId).
- M2: every codec ships native CodecDescriptor through unified codecs:
  slot; synthesis bridge, parameterizedCodecs: slot, CodecParamsDescriptor,
  aliasCodec, and arktypeJsonEmitCodec all delete; aliasDescriptor
  replaces aliasCodec.
- M3: ParamRef gains refs?: { table, column }; validator-pass enforces
  refs-required for parameterized codec ids; encode-side dispatch goes
  through forColumn; forCodecId fallback retires for parameterized codec
  ids.
- M4: JsonSchemaValidatorRegistry deletes; validation lives inline in the
  resolved codec decode body (matching the arktype-json pattern parent
  established); json-validator trait retires if no consumer remains.

Mongo registration migration is folded into TML-2324.
…me Codec instance

Mid-flight WIP from the M1 implementer subagent (implementer-m1-r1).
Captured at user request before subagent return.

Substantive shape:
- Narrow framework Codec interface: drop traits / targetTypes /
  renderOutputType? from the instance; encode TTraits as a phantom-
  symbol carrier so trait-gated downstream type machinery still works
  without a runtime field.
- Extend CodecLookup with descriptor-routed accessors
  (targetTypesFor, metaFor, renderOutputTypeFor) so consumer sites
  reach codec-id-keyed metadata without reading off the codec
  instance.
- Migrate consumer reads in framework-components/control-stack,
  emitter/domain-type-generation, mongo-codec, mongo-contract-psl,
  sql-contract-psl/provider, relational-core/ast/codec-types,
  sql-runtime/sql-context, and postgres-adapter/sql-renderer to read
  through the new accessors.
- Thread explicit { traits, targetTypes, meta } args into
  synthesizeNonParameterizedDescriptor so contributor code keeps
  compiling while the bridge survives until M2.

Known incomplete: workspace typecheck fails in
@prisma-next/mongo-codec on an unused-import lint (`ifDefined`); the
subagent has not yet completed its M1 R1 round. Pushing as a
checkpoint per user request; subagent return + cleanup will land in a
follow-up commit.
Picks up from WIP commit 692178c and lands the changes the prior
implementer needed to reach a green validation gate.

What this commit adds, on top of the WIP:

- mongo-codec: drop the unused `ifDefined` import-then-unused regression,
  re-shape `MongoCodec` to extend the narrow framework `Codec` while
  keeping `traits` / `targetTypes` / `renderOutputType` as optional
  transitional fields (per the M1 plan, these survive on family-specific
  Codec extensions until M2). Re-thread the runtime factory so
  `mongoCodec()` still emits `targetTypes` / `traits` /
  `renderOutputType` on the resolved instance for downstream consumers.
- relational-core/ast/codec-types: keep SQL `Codec` extending the narrow
  framework `Codec` and re-declare `traits` / `targetTypes` / `meta` /
  `paramsSchema` / `init` / `renderOutputType` as optional transitional
  fields for M1; `targetTypes` becomes optional throughout. Defensively
  default `codec.targetTypes ?? []` in `CodecRegistryImpl.register`.
- sql-runtime/sql-context: pass `targetTypes ?? []` into the synthesis
  bridge so a codec without that field still lifts to a descriptor.
- arktype-json: type the emit-only shim against the SQL `Codec` (which
  still carries the transitional metadata fields) rather than the
  narrowed framework `Codec`.
- adapter-postgres/codec-lookup: implement the new `CodecLookup` accessors
  (`targetTypesFor`, `metaFor`, `renderOutputTypeFor`) on top of the
  built-in postgres codec map.

Test mocks updated to fully implement the widened `CodecLookup` shape:
emitter, sql-renderer cast-policy, mongo / sql contract-psl,
contract-ts, cli config + contract-enrichment, and integration tests
(`ts-psl-parity.real-packs`, `migration-psl-authoring`). Where tests
read `codec.targetTypes` directly, they now read through
`codecLookup.targetTypesFor(codecId)`.

No production reads of the removed framework-`Codec` fields remain:
the only direct `codec.traits` / `codec.targetTypes` / `codec.meta`
reads under packages/ are the synthesis bridge call site
(sql-context.ts) and the SQL `CodecRegistryImpl.register` loop, both
operating on SQL `Codec` whose interface still carries them in M1.

Validation: `pnpm typecheck`, `pnpm lint:deps`, `pnpm test:packages`,
`pnpm test:e2e`, `pnpm build`, and demo emit byte-identical against
`origin/main` all pass.

Refs: TML-2357
…nts (D1, D2)

- Spec AC-3 § 2: split family-extension narrow across M1 (framework) /
  M2 (family extensions, alongside synthesis-bridge deletion). The
  two-stage ordering is intentional and was implicit in the plan; the
  spec now states it explicitly so future readers and the AC scoreboard
  agree on the milestone boundary.
- Plan T1.4: tighten the emit-path file list to the single production
  site on origin/main (domain-type-generation.ts). The original
  enumeration of emit.ts / emit-types.ts / generate-contract-dts.ts
  was aspirational; reviewer grep on origin/main confirmed only one
  real read site.

Sourced from m1 R1 reviewer report § Items for the user's attention
(D1, D2). Refs TML-2357.
Drops two unnecessary `as unknown as ...` casts in
`adapter-postgres/codec-lookup.ts` and tightens the existing comment
block on the genuinely-transitional cast in
`framework-components/control-stack.ts` to name F1 explicitly.

Site (1) — `definition.codec as unknown as SqlCodec` (line 22): the
`defineCodecs` builder already types `definition.codec` as the SQL
`Codec` extension, so the cast was a no-op fossil from R1 plumbing.
Drop it; `byId.set(definition.codec.id, definition.codec)` typechecks
directly.

Site (2) — `byId.get(id) as Codec | undefined` (line 25): `SqlCodec`
extends the framework `Codec`, so the lookup return type widens
without an explicit cast. Drop it; `get: (id) => byId.get(id)`
typechecks under the `CodecLookup` interface contract directly.

Site (3) — `legacyMeta = codec as unknown as LegacyCodecInstanceMeta`
in `extractCodecLookup` (line 377): genuinely transitional. The
framework `Codec` interface narrowed in M1 but family-`Codec`
extensions still carry `traits` / `targetTypes` / `meta` /
`renderOutputType` as optional transitional fields, and the assembled
`CodecLookup` has to surface them to the new descriptor-routed
accessors until every contributor ships a native `CodecDescriptor`.
Comment block now names this disposition explicitly so the next
reader knows the cast is documented M2-bundled cleanup, not a
forgotten loose end.

Validation: `pnpm typecheck`, `pnpm lint:deps`, `pnpm test:packages`,
`pnpm test:e2e`, `pnpm build`, demo emit byte-identical against
`origin/main` all pass.

Refs: TML-2357
Composes a derived CodecDescriptor by overlaying codecId, targetTypes,
and optional meta on a base descriptor. The alias factory delegates to
the base factory and rewrites `id` on the resolved codec.

Replaces the legacy `aliasCodec` helper that composed at the codec-
instance level. Lives in framework-components so SQL families can share
it without a target-specific dep.

Refs TML-2357 T2.1.
…() parallel APIs

Introduces the descriptor-shaped factory + builder in
sql-relational-core that the per-package M2 migrations will adopt,
without disturbing the legacy codec()/defineCodecs() that 28+ existing
consumers (production + tests) still depend on.

The plan T2.2 deferred the absorb-vs-parallel choice to implementation
start, biased to absorb when "structurally clean". Implementation-time
recon found absorb is not clean: 28+ direct codec() consumers would
break simultaneously and 15+ test files read transitional fields off
the resolved Codec instance. Per the plan's fallback ("only introduce
a parallel defineCodecDescriptors if defineCodecs doesn't admit a
clean shape"), this is the parallel-API path.

Setup-commit only: every existing consumer compiles and tests pass.
Per-package migrations land in subsequent commits; the M2 cleanup
commit deletes both the legacy and parallel APIs once the migration
chain finishes.
…nal-core base codecs

Each of the six SQL base codecs (char, varchar, int, float, text,
timestamp) gains a sibling `*Descriptor` export authored natively via
`codecDescriptor()`. The descriptor builder is wired through
`defineCodecDescriptors()` and exposed as `sqlCodecDescriptorDefinitions`
and `sqlCodecDescriptorList` (mirroring the legacy `sqlCodecDefinitions`).

Encode/decode/render functions are extracted to module-level constants
so the legacy codec form and the descriptor form share a single source
of runtime behaviour during the migration window. The legacy codec
exports stay so postgres + sqlite + sql-codecs.test.ts keep compiling;
they migrate to the descriptor exports in subsequent per-package
commits and the legacy form deletes in the M2 cleanup.

Adds an `AnyCodecDescriptor` variance-erasure alias to `codec-types.ts`
so the descriptor builder can collect heterogeneous descriptors (the
descriptor `factory` and `renderOutputType` slots are contravariant in
`P`, so heterogeneous storage cannot use `CodecDescriptor<unknown>`).
…rget codecs

Each of the 22 postgres codecs gains a sibling `*Descriptor` definition
authored via `codecDescriptor()` (or composed from a base SQL descriptor
via `aliasDescriptor`). The descriptor builder is wired through
`defineCodecDescriptors()` and exposed as `codecDescriptorDefinitions`
and `codecDescriptorList`, mirroring the existing `codecDefinitions` /
`dataTypes` shape.

The legacy `Codec` instances + `aliasCodec` helper stay so the postgres
adapter (codec-lookup.ts, runtime.ts, descriptor-meta.ts, adapter.ts)
and the postgres test suite keep reading codec instances out of
`codecDefinitions[k].codec` until the unified `codecs:` slot reshape
(later in M2). Both shapes retire to descriptor-only in the M2 cleanup
commit.
…et codecs

Each of the seven sqlite codecs (text, integer, real, blob, datetime,
json, bigint) gains a sibling `*Descriptor` authored via
`codecDescriptor()`. The descriptor builder is wired through
`defineCodecDescriptors()` and exposed as `codecDescriptorDefinitions`
and `codecDescriptorList`, mirroring the existing `codecDefinitions` /
`dataTypes` shape (and reusing the shared SQL base descriptors —
char, varchar, int, float — by reference).

The legacy `Codec` exports stay so the sqlite adapter (codec-lookup,
runtime-adapter, adapter) and the sqlite test suite keep reading
codec instances out of `codecDefinitions[k].codec` until the unified
`codecs:` slot reshape later in M2; both shapes retire to descriptor-
only in the M2 cleanup commit.
The vector codec gains a native `pgVectorDescriptor` authored via
`codecDescriptor()` in core/codecs.ts (with `paramsSchema` and
`renderOutputType` consolidated into the descriptor). The runtime
extension drops its hand-rolled descriptor literal and references
`pgVectorDescriptor` directly; the legacy `parameterizedCodecs:` slot
still echoes the descriptor through the `RuntimeParameterizedCodecDescriptor<P>`
alias for the contributor protocol.

Both the legacy `codecDefinitions[k].codec` surface and the new
`codecDescriptorList` ship through this commit; the M2 cleanup commit
collapses the parameterized + non-parameterized slots into the unified
`codecs:` slot.
`arktypeJsonCodec` is already authored as a native parameterized
`CodecDescriptor`. The emit-only `Codec` instance (`arktypeJsonEmitCodec`)
that pack-meta threaded under `codecInstances` for the framework
emitter's legacy `CodecLookup` retires here — M1 routed emit through
`descriptorFor(codecId).renderOutputType`, so the shim has been dead
code at runtime.

Removes:
- `arktypeJsonEmitCodec` export and its private
  `renderArktypeJsonOutputTypeFromUnknownParams` permissive renderer.
- `codecInstances: [arktypeJsonEmitCodec]` from `pack-meta.ts`.
- The `arktypeJsonEmitCodec` describe block + the
  `threads ... into codecInstances` test in `arktype-json-codec.test.ts`.

The legacy `parameterizedCodecs:` slot still exposes the descriptor
through `arktype-json/src/exports/runtime.ts`; the unified `codecs:`
slot reshape lands later in M2.
Reshape the SQL contributor protocol so every codec - parameterized or
not - flows through a single `codecs: () => ReadonlyArray<AnyCodecDescriptor>`
slot. Delete the legacy `parameterizedCodecs:` slot from
`SqlStaticContributions` and from every contributor (postgres + sqlite
targets and adapters, pgvector + arktype-json extensions). Delete the
`synthesizeNonParameterizedDescriptor` bridge and its sole production
consumer in `sql-context.ts`; the runtime now indexes the unified
descriptor list directly into `CodecDescriptorRegistry`, and partitions
parameterized vs. non-parameterized by reference-equality with
`voidParamsSchema` (a singleton that only the framework supplies for
default `codecDescriptor()` cases).

Closes AC-1 (synthesis bridge deleted) and AC-2 (parameterizedCodecs
slot deleted) of TML-2357.

Notes:
- Add `AnyCodecDescriptor = CodecDescriptor<any>` to framework-components
  as the variance-erased alias for heterogeneous descriptor collections;
  re-export from `framework-components/codec`.
- `codecDescriptor()` now attaches `traits`/`targetTypes`/`meta`/
  `renderOutputType` to the materialized codec instance so consumers
  that still read those fields off the codec (e.g. `extractCodecLookup`
  in `framework-components/control-stack`) see the same shape they get
  from the legacy `codec()` factory. The attachment retires alongside
  the family-extension narrow in Phase B.
- `sql-context.ts` materializes a representative codec for every
  descriptor whose factory tolerates `undefined` (pgvector ignores
  params), so `forCodecId` keeps a fallback for refs-less call sites
  (the AC-5 carve-out path); descriptors whose factory needs real
  params (arktype-json) raise and are skipped, deferring to lazy
  per-column materialization.
- pgvector runtime descriptor now materializes its `codecInstances`
  through `pgVectorDescriptor.factory({length: 0})({name})` so
  `extractCodecLookup` continues to discover the `pg/vector@1` codec
  on the runtime plane (`$N::vector` cast policy).
- Tests migrated: `contract-codec-registry`, `execution-stack`,
  `json-schema-validation`, `mutation-default-generators`,
  `parameterized-types`, `sql-context`, `sql-runtime-abort`,
  `sql-runtime`, `pgvector/operations`, `arktype-json/extension-descriptors`,
  `adapter-postgres/{adapter,descriptor-parity}`, `integration/pgvector`.
  The legacy synthesis-bridge consumer in test fixtures retires through
  a test-only `descriptorsFromCodecRegistry` helper in `sql-runtime/test/utils`,
  scheduled to delete with the family-extension narrow in Phase B.
- `RUNTIME.DUPLICATE_PARAMETERIZED_CODEC` collapses to `RUNTIME.DUPLICATE_CODEC`
  (one error code for the unified registration path).

Validation: typecheck + lint:deps + sql-runtime/test:packages,
adapter-postgres/test, adapter-sqlite/test, sql-orm-client/test,
pgvector/test, arktype-json/test all green at this commit.
…lot refs

The unified `codecs:` slot landed in M2 Phase A; the supporting symbols
that named the legacy split slot or the adapter-level params descriptor
no longer have any consumers. Delete the residue so the cross-package
grep gate goes empty:

- `CodecParamsDescriptor` interface and the file-local doc references
  to it / to the (already-removed) `Adapter.parameterizedCodecs()`
  surface in `relational-core/ast/codec-types.ts`.
- `aliasCodec` helper in `target-postgres/core/codecs.ts`. The four
  call sites (`pgChar`/`pgVarchar`/`pgInt`/`pgFloat`) inline-spread the
  base SQL codec and override `id` / `targetTypes` / `meta`. Cast
  through `unknown as Codec<typeof PG_*_CODEC_ID>` because the literal
  override conflicts structurally with the base codec's literal id.
- Test variables named `parameterizedCodecs` rename to `descriptors` in
  `parameterized-types.test.ts` and `json-schema-validation.test.ts` to
  match the unified-slot vocabulary.
- Doc comments referencing the legacy slot in `sql-context.ts`,
  `arktype-json/{src/core,src/exports}/runtime.ts`, `pgvector/src/core/codecs.ts`,
  `framework-components/shared/codec-types.ts`, and the postgres
  adapter test rephrase to describe the unified slot.

The threading-ctx test in `parameterized-types.test.ts` had been
failing at HEAD because Phase A introduced a representative-codec
materialization in `createExecutionContext` (factory(undefined) call
to populate the legacy `forCodecId` fallback registry); the test
captured every factory call and asserted on `observedCtxs[0]`.
Replace with a `find` by the per-column ctx name (`Vector1536`) so
the assertion targets the per-column factory call rather than the
representative materialization.

Family-extension `Codec` field-set narrow (AC-3) and the legacy
`codec()` / `defineCodecs()` factory deletion remain as a follow-up
round — surfaced separately to the orchestrator. The cross-package
grep for `synthesizeNonParameterizedDescriptor|CodecParamsDescriptor|aliasCodec|arktypeJsonEmitCodec|parameterizedCodecs`
across `packages test examples --type ts` is now empty.

Refs: TML-2357
Adds a `codecDescriptors` slot on `ComponentMetadata.types.codecTypes`
alongside the existing `codecInstances` slot, and rewires
`extractCodecLookup` to prefer the descriptor list. SQL contributors
(Postgres adapter, pgvector control + runtime) now expose the unified
descriptor list; the codec-instance fallback stays for Mongo and any
other contributor that has not migrated to descriptors.

Materializes a representative `Codec` per descriptor (where the factory
tolerates `undefined` params) so `byId.get()` keeps surfacing instances
for the SQL renderer cast-policy lookup. Parameterized factories that
need real params are populated lazily by the runtime registry build.

Refs: TML-2357 M2 Phase B
`codecDescriptor()` no longer attaches `traits` / `targetTypes` /
`meta` / `renderOutputType` to the materialized `Codec`. The
descriptor-side metadata is now read by `extractCodecLookup` directly,
so the bolt-on is unused.

Refs: TML-2357 M2 Phase B
wmadden added 28 commits May 9, 2026 07:49
…re rename and scrub class-form vocabulary

The earlier per-package F9+F10 commit renamed the core file
(arktype-json-codec-class.ts → arktype-json-codec.ts) but left a few
sibling import paths still pointing at the old path. This commit
realigns those (pack-meta.ts, registry.ts, exports/codecs.ts,
exports/column-types.ts, exports/control.ts).

Test files renamed alongside the core: arktype-json-codec-class.test.ts
→ arktype-json-codec.test.ts and arktype-json-codec-class.types.test-d.ts
→ arktype-json-codec.types.test-d.ts. The internal JSDoc reference in
arktype-json-codec.ts is updated to point at the new test path.

Comment vocabulary scrubbed: "class-based" / "class-form" comments are
removed or rephrased in the test files and the descriptor-list comment
in extension-descriptors.test.ts.

Closing-grep "arktype-json-codec-class" is now 0.
Final F10 cleanup: drops the residual transition vocabulary from the
SQL relational-core / runtime layers and the codec authoring guide.

Implementation files:
- relational-core/src/ast/sql-codecs.ts and sql-codecs-class.ts: header
  comments rephrased.
- relational-core/src/ast/codec-types.ts: two JSDoc blocks rephrased
  (SqlCodecCallContext, ExtractCodecTraits) — "class-form codec methods"
  and "class-form codecs" wording dropped.
- 5-runtime/src/sql-context.ts: "non-parameterized class-form descriptor"
  → "non-parameterized descriptor" in the partition heuristic doc.
- relational-core/README.md: stale "core/codecs-class.ts" path reference
  updated to the renamed core/codecs.ts.

Tests:
- relational-core sql-codecs-class.types.test-d.ts and typed-codec-flow.test-d.ts:
  description headers rephrased.

Docs:
- docs/reference/codec-authoring-guide.md: stale arktype-json
  `core/arktype-json-codec-class.ts` reference updated to the renamed
  path; the descriptor instance in the worked example renamed to match
  the implementation (arktypeJsonDescriptorClass → arktypeJsonDescriptor).

"class" stays where it refers to the actual class declaration site or
the abstract-class structural relationship (Pattern E authoring
discussion in codec-authoring-guide.md, framework-components/test/
codec.test.ts, sql-orm-client async-dispatch tests, and ADR historical
records).

Closing-grep table:
- codecDescriptorClassList = 0
- DescriptorClass\\b in packages/ = 0 (stays in docs/reference example
  prose if any; the worked example was updated)
- core/codecs-class = 0
- arktype-json-codec-class = 0
- Class-form / class-based in implementation = 0
- export \\* from core/codecs in any exports/codecs.ts = 0
…odec-async tests

Two codec-async test-doc comments still referenced "class-form codec
base"; the underlying object they describe is the framework codec base
(CodecImpl), so the precise word is just "codec base". The structural
abstract-class reference would still apply if the comment named the
class directly (`CodecImpl`), but the bare "class-form" phrasing is
the same transition vocabulary the rest of F10 is dropping.

Closing-grep "class-form" in packages/ is now 0.
…le split)

Apply the same helper-module split that postgres / sqlite did under F10:

- ast/sql-codecs.ts (helpers + codec id literals) -> ast/sql-codec-helpers.ts
- ast/sql-codecs-class.ts (codec descriptor classes) -> ast/sql-codecs.ts

Updates:
- src/ast/sql-codecs.ts internal import realigned to ./sql-codec-helpers
- exports/ast.ts re-exports both files under their new names
- test files renamed in lockstep:
  - test/ast/sql-codecs.test.ts -> test/ast/sql-codec-helpers.test.ts
  - test/ast/sql-codecs-class.test.ts -> test/ast/sql-codecs.test.ts
  - test/ast/sql-codecs-class.types.test-d.ts -> test/ast/sql-codecs.types.test-d.ts
- typed-codec-flow.test-d.ts and postgres JSDoc references realigned

Closing-grep on \\bsql-codecs-class\\b in packages/ now zero hits.

Closes finding F11.
…ma helper

The arktypeParamsSchema cast helper existed only because the arktype
schemas declared parameter keys as required while the framework TParams
types declared them optional+readonly (F20). Fix the structural
mismatch directly: tighten every arktype params schema to use the
"key?" optional syntax where the matching TParams declares the key
optional, then assign the schema directly to paramsSchema with an
explicit StandardSchemaV1<TParams> type annotation.

Concrete changes:

- Tighten lengthParamsSchema in sql-codecs.ts and postgres core/codecs.ts
  to use "length?": "number.integer > 0" (matches LengthParams optional).
- All arktype schemas now satisfy StandardSchemaV1<TParams> directly via
  arktype Type's built-in standard-schema integration (~standard slot).
- Delete arktypeParamsSchema cast helper at
  packages/1-framework/0-foundation/contract/src/standard-schema-utils.ts
  and remove its re-export from exports/types.ts.
- Update the four consumer sites (postgres, sql-relational-core,
  pgvector, arktype-json) to assign the arktype schema directly with
  an explicit `: StandardSchemaV1<TParams>` annotation.
- Add @standard-schema/spec dep to pgvector + arktype-json packages
  (was previously transitively pulled through @prisma-next/contract's
  arktypeParamsSchema return type).

Note on dropping arktype runtime dep from @prisma-next/contract: the
contract package's validate-contract.ts uses arktype directly for
structural validation, so the arktype dep stays in @prisma-next/contract.
F13's structural cleanup of the cast helper is achieved; full removal
of arktype from the foundation closure requires a separate refactor
of validate-contract.ts.

Closing-grep on arktypeParamsSchema in packages/ now zero hits (only
remaining reference lives in docs/reference/codec-authoring-guide.md,
addressed by F16).

Closes findings F13, F14, F20.
…d callback

The previous implementation derived `isParameterized` at the SQL runtime
boundary by carrying an `IsParameterizedCodecId` callback into
`validateParamRefRefs`. That coupled validation to a SQL-flavoured set
helper and forced every consumer that wanted parameterization status to
rebuild it from the registry, leaking schema knowledge sideways.

Codec parameterization is intrinsic to the descriptor (it is set when
the descriptor is authored: `paramsSchema === voidParamsSchema`), so the
flag belongs on `CodecDescriptor` itself. `CodecDescriptorImpl` now
exposes it as a getter computed from `paramsSchema`; descriptors built
ad hoc (factories, test fixtures, the mongo adapter) declare the flag
explicitly. `validateParamRefRefs` now takes a `CodecDescriptorRegistry`
and reads `descriptorFor(id)?.isParameterized`, so SQL runtime no longer
maintains a parallel set.

Test fixtures across `framework-components`, `sql-relational-core`,
`sql-runtime`, `sql-orm-client`, `mongo-adapter`, and `adapter-postgres`
were updated to populate the new property; non-parameterized stubs use
`isParameterized: false`, the pgvector test descriptors use `true`.

Closes F12.
`Codec.[codecTraitsPhantom]?: TTraits` relied on a `unique symbol`
declared at module scope. Symbol identity is tied to the declaring
module path, so under bundlers that split declaration files (the same
TS2742 family that motivated the F8 `Resolve<T>` materialisation) a
consumer-side `pack.d.mts` can end up referencing a chunk-private path
for the symbol identity.

Replace the symbol with a double-underscored string-key phantom slot
(`readonly __codecTraits?: TTraits`). The double underscore signals the
slot is implementation-detail only; it remains optional and `undefined`
at runtime, so the source-of-truth remains `descriptor.traits`. The
`codec-types` jsdoc that referenced the symbol-keyed slot was updated
in lockstep, and the type-d test that enumerated `keyof Codec` was
extended to include the string-keyed phantom.

Closes F15.
The Aliases section described a "small file-local `aliasCodec` helper"
that uses `Object.create` + `Object.assign` + `Object.defineProperty`
to derive an aliased instance. That helper does not exist anywhere in
the repo (`Grep aliasCodec` returns zero hits in `packages/`); the
current alias mechanism is plain `class … extends BaseDescriptor` with
`override readonly codecId = …` plus any other metadata the alias
needs.

Replace the stale prose with a worked example showing the descriptor-
class-inheritance shape, explain why the prototype-stripping bug it
historically guarded against is structurally avoided (descriptor
inheritance never spreads), and link the canonical postgres alias
example. The reference list at the bottom of the file already points
at the post-F10 filenames so no further path updates are needed.

Closes F16.
The postgres `core/codecs.ts` preamble said the codec classes "wrap the
module-level encode/decode/encodeJson/decodeJson constants exported
from `codecs.ts`" — but the file is itself `codecs.ts` after the F10
rename; the helpers moved to `codec-helpers.ts`. Update the reference
so contributors arriving at this file find the helper module on the
first hop.

Sqlite has no analogous problem: its codec class bodies inline their
conversions and the preamble says so explicitly.

Closes F17.
The test name claimed `field.id.uuidv4()` produces a "string-typed id
field on User", but the assertions only verified property presence
(`toHaveProperty(column)`). That left AC-CB-6 without an evidence test
that pinned the no-emit chain to the typed leaf — any field whose IR
carries a `column` slot would have passed.

Add an `expectTypeOf<IdField[column]>().toExtend<string>()` assertion
plus a `not.toBeNever()` guard. `toExtend` rather than `toEqualTypeOf`
because the storage column type narrows further than the bare `string`
constraint (codec-typed leaves can carry stricter brand/literal info
than `string`); `not.toBeNever` catches the failure mode where codec
lookup mis-resolves and the leaf widens to bottom.

Closes F18.
Four related issues in control-stack.ts and its test fixture:

F19 - the try/catch block in the byId-materialization loop swallowed
every factory failure as the "needs concrete params" case. A registered
codec whose factory threw for any other reason (genuine bug, missing
dep, runtime error) silently disappeared from byId, then
codecLookup.get() consumers misclassified it as unregistered. Now that
F12 surfaces descriptor.isParameterized on every descriptor, we skip
parameterized factories proactively and let other failures surface as
real errors. The non-parameterized path no longer catches.

F31 - the inline import("../shared/codec").Codec and friends bypassed
the file's normal top-of-file import grouping. Lift Codec and CodecMeta
to top-of-file imports.

F32 - extractCodecLookup accepted Pick<ComponentMetadata & { id?:
string }, "types" | "id"> and fell back to descriptor.id ?? "<unknown>".
Every real call-site supplies a defined id. Tighten the parameter to
require id: string; the "<unknown>" sentinel was defensive coding that
masked a missing-id bug rather than handling a real case.

F33 - same inline-import hygiene as F31, applied to the test file.
Lift Codec, AnyCodecDescriptor, and StandardSchemaV1 to top-of-file
imports.

Closes F19, F31, F32, F33.
profile.codecs() returned a fresh emptyCodecRegistry() every call,
which dropped any codecs registered through a prior codecs() reference.
Tests that exercised the registry across calls became order-dependent
and would silently miss registrations.

Capture the registry once in the closure and return that stable
reference; document why in the doc comment.

Closes F21.
Three coupled findings on AC-5 / AC-CB-2:

F29 — pgvector's PgVectorCodec ignored params.length: factory(_params)
returned a closure that never threaded the dimension into the codec,
so vector(3) and vector(1536) produced behaviourally identical codecs
and a length-mismatched value round-tripped undetected. Thread length
into the constructor and add an `assertVector` guard that runs on
every ingress (encode, decode, encodeJson, decodeJson) so a wrong-
dimension or non-numeric value surfaces as an explicit error rather
than silently propagating.

F26 — refsFromLeft only matched bare column-ref expressions and
returned undefined for any wrapping shape (BinaryExpr, MethodExpr,
function calls). The validator pass would then fail or fall through to
forCodecId for predicates like `eq(upper(f.id), value)` whose left
side is a single-column-derived expression. Walk the expression with
`collectColumnRefs()` and accept the unique ref when present, so
column-bound predicates that stay on a single column preserve refs;
genuinely ambiguous shapes (`eq(concat(a, b), value)`) still return
undefined. Replace inline `...(x !== undefined ? { x } : {})` spreads
in `param`/`paramList` with the `ifDefined` helper from
`@prisma-next/utils/defined`.

F22 — encode-side / decode-side resolution code on a `forColumn` miss.
The original concern was that falling through to `forCodecId` could
silently pick a representative for a parameterized id. After F19
(extractCodecLookup skips parameterized descriptors) and given
`buildContractCodecRegistry`'s `ambiguousCodecIds` rejection plus its
column-correct `byCodecId` materialization, the wrong-instance risk is
closed off structurally — fall-through now resolves either to the
column-correct per-instance codec (single-column parameterized) or
throws (ambiguous parameterized). Document the structural argument in
both `resolveParamCodec` and `resolveProjectionCodec` so future
contributors see why fall-through is principled here.

The pgvector test fixture is updated to construct the codec at the
dimension matching its value array, plus two new tests pinning the
length-mismatch error path that F29 introduces.

Closes F22, F26, F29.
F23 — rehydrateSchema returned `ark.schema(jsonIr) as unknown as
ArktypeSchemaLike`. The double cast hid runtime shape uncertainty:
ark.schema returns a BaseRoot whose runtime callability and
`expression: string` slot aren't statically guaranteed by arktype's
public types. Introduce an explicit `isArktypeSchemaLike` guard
between the rehydrate call and the return; surface a
RUNTIME.JSON_SCHEMA_VALIDATION_FAILED envelope if the runtime shape
doesn't match (with the offending jsonIr in details for debugging).

F24 — the negative-path test used `arktypeJsonColumn(notASchema as
any)` plus a `biome-ignore lint/suspicious/noExplicitAny` suppression.
The repo TS rules prohibit both. Replace with `@ts-expect-error` and
drop the cast.

F25 — the type-d test used `toMatchTypeOf`, which is deprecated in
vitest's expectTypeOf API. Replace with `toExtend`, which expresses
the same subtype relation under the current API.

Closes F23, F24, F25.
Why: when two components contribute the same `codecId` (target +
extension, two extensions, etc.) the previous build silently let the
last writer win. That meant a real registration mistake — easy to make
in a multi-pack project — produced a registry that *looked* fine but
silently dropped one descriptor's metadata, breaking codec resolution
in subtle ways downstream.

Behaviour change: `buildCodecDescriptorRegistry` now throws an `Error`
with the offending codecId on duplicate registration. Each codec
identifier must be contributed by exactly one component (target /
adapter / extension pack); collisions are a configuration bug and
should fail fast at registry construction.
…at exports

Why: `codecDescriptorMap` is implementation detail — it shouldn't sit
on the public package surface. F8 deliberately put `Resolve<T>` at
`exports/` so tsdown's DTS bundler resolves consumer-side `pack.d.mts`
references via the public entry point rather than a hash-named
internal chunk (the `TS2742` family F8 closed). Moving the map alone
into `core/` while keeping the `Resolve<...>` application at
`exports/codec-types.ts` preserves both invariants:

- Internal detail (the descriptor map and the `Resolve<T>` helper
  itself) lives in `core/codec-type-map.ts`.
- The public boundary still materialises `CodecTypes = Resolve<...>`,
  so the DTS bundle anchors consumer references at the public entry.

Verified: `pnpm typecheck` 123/123 PASS; `target-postgres` build
emits no TS2742 portability errors; downstream consumers
(`prisma-next-demo`, sql-orm-client tests) still typecheck clean.
Why: F19's strict isParameterized skip turned out to regress the
contract emitter's literal-default encoding path. The emitter calls
`codecLookup.get(codecId).encodeJson(value)` to canonicalize default
values into the JSON contract — for `pg/timestamptz@1` (precision-
parameterized but factory ignores params) the lookup miss caused
`new Date(...)` to fall through unencoded and serialize as `{}`,
losing the literal Date value in `contract.json` and the typed
`DefaultLiteralValue<...>` in `contract.d.ts` (e2e fixture drift).

Refinement keeps F19's intent (don't mask real factory bugs in
non-parameterized codecs) while restoring representative
materialization for parameterized codecs whose factory tolerates
empty params:

- Non-parameterized: factory must succeed; any throw propagates as a
  real bug. (No try/catch — F19's silent-catch concern preserved.)
- Parameterized: try with empty params; codecs that treat params as
  advisory (e.g. `pg/timestamptz@1` where precision only affects the
  rendered native type) yield a usable representative for id-keyed
  lookups (emit-time literal-default encoding). Codecs whose factory
  genuinely requires params (e.g. `pg/vector@1` after F29 threading
  `length` into the runtime codec) throw and skip — per-column
  instances are materialized at runtime by `buildContractCodecRegistry`
  and the id-keyed lookup miss is the correct outcome (the column-
  aware path resolves them).

Validates: `pnpm fixtures:check` clean, `pnpm typecheck` 123/123.
Why: three input-validation gaps in the postgres codec helpers
allowed nonsense to reach `contract.d.ts` / runtime decode without
surfacing a clear diagnostic at the boundary.

F34: `pgNumericRenderOutputType` validated `precision` (finite,
integer) but let `scale` fall through to `typeof === 'number'` only.
`Numeric<10, NaN>` / `Numeric<10, Infinity>` / `Numeric<10, 0.5>`
emitted into `contract.d.ts` for invalid inputs. Mirrors the
precision validation onto scale.

F35: `pgTimestamp{,tz}DecodeJson` only checked that `json` is a
string and `new Date(json)` is not `Invalid Date`. The error message
claimed "Expected ISO date string" but the function accepted any
format the `Date` constructor could parse (`January 15, 2024`,
`01/15/2024`, etc.) — implementation-defined, browser-specific, and
not the documented contract. Adds an `ISO_8601_UTC` regex gate before
constructing the `Date`. Permits optional fractional seconds;
trailing `Z` required. Does not use `date.toISOString() === json` as
a round-trip check — that would incorrectly reject valid ISO inputs
without milliseconds.

F36: `pgEnumRenderOutputType` ran `String(value)` over every entry in
`values`, accepting numbers / objects / `null` / `undefined` and
emitting `'1' | '[object Object]' | …` literal unions. Combined with
F39 (the `enumParamsSchema` accepts `unknown[]`), PSL emit could
produce nonsense union types. Validates every element is a string
before rendering; drops the `String(...)` coercion in the map.

Tests: existing `target-postgres` tests continue to pass (201/201);
no regression to sqlite (84/84).
Why: `decode(wire: string)` was returning `new Date(wire)` without
validating; `new Date('not-a-date')` returns an `Invalid Date` whose
`.getTime()` is `NaN`. The codec's typed return is `Date`, so
consumers received an object whose downstream operations silently
produced `NaN` — same failure shape as F35 on the postgres side, but
this codec did not have any guard at all.

Adds a private `parseDate` helper that throws on `NaN`-time, and
threads it through both `decode` (wire path) and `decodeJson` (JSON
path) so every Date ingress is validated. Encode paths stay as-is —
they receive a `Date` from the input layer and forward it.

Tests: existing `target-sqlite` tests continue to pass (84/84).
Why: `enumParamsSchema = arktype({ 'values?': 'unknown[]' })`
validated the JSON-boundary shape as `readonly unknown[]`, but
PostgreSQL enum members are by definition strings. The looser shape
let nonsense (numbers, objects, `null`) reach the renderer.

`'string[]'` tightens the contract at the JSON boundary, surfacing
the real error there instead of letting the render path absorb it.
Combined with F36 (string-element check inside
`pgEnumRenderOutputType`), the schema becomes the single gate for
enum value shape — the renderer's check is the in-depth fallback.

Mirrors the type narrowing on `EnumParams` (`readonly unknown[]` →
`readonly string[]`) so the descriptor's `paramsSchema` `satisfies`
clause typechecks against a concrete shape.
…egistry

The previous register(codec) method on the SQL CodecRegistry interface was
used in a strict build-then-read pattern: every consumer assembled a fresh
registry once and then read from it. The mutation surface was exposed
externally but never used to overwrite or alter a live registry post-read.

Collapse the surface to a single-shot builder:

- Add buildCodecRegistry(codecs: readonly Codec<string>[]): CodecRegistry
  that returns a read-only registry built once from the input array.
- Drop register(codec) from the CodecRegistry interface; drop the
  newCodecRegistry() factory (no remaining consumers).
- Migrate the production SQL execution-context construction in
  sql-context.ts and the postgres / sqlite adapter codec-registry
  closures to assemble a Codec[] up-front and call buildCodecRegistry
  once.
- Migrate the ~25 test fixtures (sql-runtime, relational-core,
  sql-orm-client, integration) to the same up-front-array + builder
  pattern. The pattern was mechanical — repeated registry.register(codec)
  calls collapse into a single array literal passed to the builder.

No behavioural change: duplicates still raise on construction; the
returned registry exposes the same get/has/values/iterator surface.
…criptorRegistry

After Phase 1 narrowed CodecRegistry to a build-then-read map of resolved
Codec instances, audit every CodecRegistry.get(id) consumer to determine
whether the resolved-instance contract is still required:

- ExecutionContext.codecs (sql-runtime): purely a relay to encode/decode
  call sites. Migrate-able (a) — replace with direct ContractCodecRegistry
  lookup at the encode/decode call site.
- encodeParam / decodeRow registry parameter (sql-runtime): hot-path
  dispatch. Migrate-able (a) — pre-populate ContractCodecRegistry.byCodecId
  with one canonical instance per non-parameterized descriptor at registry
  build time, so forCodecId(id) covers refs-less call sites without an
  external registry parameter.
- AdapterProfile.codecs (lane core): test instrumentation only — no
  production consumers post Phase 1. Replaced by a test-only StubAdapter
  shape that exposes the codec array directly.

No surviving (c) consumers. Retire the CodecRegistry interface and the
buildCodecRegistry factory entirely:

- Drop CodecRegistry / buildCodecRegistry from
  @prisma-next/sql-relational-core/ast.
- Drop AdapterProfile.codecs() (test-only surface).
- Drop ExecutionContext.codecs (lane-core query-lane-context); call sites
  read context.contractCodecs / context.codecDescriptors instead.
- Drop the registry parameter from encodeParam / encodeParams / decodeRow /
  buildDecodeContext / resolveProjectionCodec / resolveParamCodec.
- buildContractCodecRegistry now pre-populates byCodecId with non-
  parameterized canonical instances and a parameterizedRepresentatives
  fallback for parameterized descriptors whose factory tolerates
  factory(undefined). Refs-less forCodecId(id) lookups read both maps;
  parameterized descriptors that need real params (arktype-json, pgvector)
  fall through to column-aware dispatch via forColumn(table, column).
- Postgres / SQLite adapters drop their internal codec-registry closures.
- sql-orm-client model-accessor and sql-family-adapter tests drop the
  legacy codecs lambda from their test contexts.
- Cross-family integration test exercises the codec directly rather than
  going through the SQL CodecRegistry.

Migrate ~25 test fixtures across sql-runtime / sql-orm-client /
relational-core / integration to:
- Pass the codec array directly (replaces buildCodecRegistry([...]) calls).
- Use buildTestContractCodecs(codecs) to construct a ContractCodecRegistry
  for tests that exercise encode/decode paths.
- Use descriptorsFromCodecs(codecs) to build a CodecDescriptorRegistry.

The descriptor-parity test in adapter-postgres becomes obsolete (it asserted
parity between AdapterProfile.codecs() and the descriptor list, which no
longer exists) and is deleted.

Net effect: a single codec registry — CodecDescriptorRegistry — survives.
The runtime materializes resolved Codec instances on demand through
ContractCodecRegistry, which combines column-aware dispatch (forColumn)
with descriptor-derived canonical instances (forCodecId).

Cross-package gates pass:
- grep "registry\.register" packages/ — no SQL CodecRegistry hits remain
  (only unrelated mongo / operations / pgvector op registries).
- grep "interface CodecRegistry" packages/ — 0 hits in SQL family.
- grep "buildCodecRegistry|newCodecRegistry" packages/ — 0 hits.
…rebase

- psl-column-resolution.ts: ColumnDescriptor typeParams accepts undefined to match framework-components ColumnTypeDescriptor under exactOptionalPropertyTypes.
- intercept-decoding / marker-vs-intercept-ordering tests: replace retired createCodecRegistry/codec/parameterizedCodecs surface with defineTestCodec + descriptorsFromCodecs (the post-M2 codec registration shape).
- sql-context tests: drop parameterizedCodecs and createCodecRegistry residue from new mutation-default-generator stability tests.
- target-postgres codecs.test.ts: route the new bytea cases through codecForScalar like its siblings (codecDefinitions never existed on this branch).
Codec-authored RUNTIME.DECODE_FAILED and RUNTIME.ABORTED were being
double-wrapped (or coerced) by decodeFields catch. Rethrow runtime
envelopes unchanged; only wrap foreign errors.

Closes CodeRabbit thread on decoding.ts:263.
…hrough

The pre-existing codec-async test asserted the old (regression) behaviour
where decodeField double-wrapped a codec-authored
RUNTIME.JSON_SCHEMA_VALIDATION_FAILED into RUNTIME.DECODE_FAILED. With
F40 in place, codec-authored runtime envelopes pass through unchanged,
so the assertion now pins the correct surfaced code + details directly.
descriptor.paramsSchema !== voidParamsSchema is brittle — any descriptor
that doesn't reuse the exact singleton gets misrouted. Use the
descriptor.isParameterized getter (F12) as the canonical discriminator.

Closes CodeRabbit thread on sql-context.ts:282.
The byCodecId pre-populated representative was being reused for every
forColumn(table, column) entry, so non-parameterized descriptors saw
the shared context instead of the real column site even on
column-aware dispatch. Keep the representative as the forCodecId
fallback only; materialise fresh instances for forColumn entries with
the column-bound SqlCodecInstanceContext (name: <col:table.column>,
usedAt: [{ table, column }]).

Closes CodeRabbit thread on sql-context.ts:427 (also applies to 492-512).
Vector<0> and Vector<-1> previously rendered through the guard. Tighten
to require length > 0. Fix is local to mongo adapter renderOutputType;
parallel guards (e.g. pgvector) are out of scope for this thread.

Closes CodeRabbit thread on mongo-adapter codecs.ts:124.
@wmadden wmadden force-pushed the tml-2357-codec-registration-model-complete-the-unified branch from 0e3aafc to c99c1ba Compare May 9, 2026 06:07
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/architecture docs/adrs/ADR 204 - Single-Path Async Codec Runtime.md (1)

43-56: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify this section as historical to avoid implying defineCodec() is current.

This section reads as present-day behavior (defineCodec() lifting sync methods), but the retrospective note says that authoring surface is retired. Please mark these statements as historical-era mechanics so the ADR stays internally consistent.

As per coding guidelines, "**/*.{md,mdx}: Keep docs current (READMEs, rules, links)`."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/architecture` docs/adrs/ADR 204 - Single-Path Async Codec Runtime.md
around lines 43 - 56, This section currently describes
defineCodec()/mongoCodec() and the Codec interface as if they are current; mark
these sentences as historical by adding a short qualifier (e.g., "Historical:",
"Legacy behavior:", or "Former design:") before the paragraph that explains that
defineCodec() lifts sync methods to Promise-returning query-time methods and the
listed Codec shape (encode/decode behavior), and update any present-tense verbs
to past-tense for symbols like defineCodec(), mongoCodec(), Codec, encode,
decode, encodeJson, decodeJson so it clearly reads as retired/legacy mechanics
rather than current behavior.
🧹 Nitpick comments (2)
docs/architecture docs/adrs/ADR 204 - Single-Path Async Codec Runtime.md (1)

237-237: ⚡ Quick win

Move implementation mechanics out of the ADR body.

This line includes concrete internal wiring and file-path implementation detail. Prefer keeping ADR text at decision/constraint level and linking to subsystem docs for mechanics.

Based on learnings, "ADRs in prisma/prisma-next should document architectural design decisions and the key constraints/assumptions only. Do not include implementation algorithms, emitter derivation logic, or step-by-step derivation/migration rules."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/architecture` docs/adrs/ADR 204 - Single-Path Async Codec Runtime.md at
line 237, The ADR includes low-level wiring and file-path detail; remove the
implementation mechanics and file paths and rephrase to the decision/constraint
level: state that component descriptors declare codecs
(ComponentMetadata.types.codecTypes.codecDescriptors), the framework aggregates
those via the execution-stack into a single MongoCodecRegistry exposed on the
execution context (context.codecs) by createMongoExecutionContext, and that
MongoRuntimeOptions no longer accepts a codecs field; move the detailed folding
algorithm and any package/file-specific implementation (e.g., the previous
package paths) into a linked subsystem implementation doc instead of the ADR
body.
docs/architecture docs/adrs/ADR 208 - Higher-order codecs for parameterized types.md (1)

166-175: ⚡ Quick win

Move the numbered runtime build sequence out of the ADR.

This section drops into implementation algorithm detail (forColumn prebuild steps, caching order, and validation flow) rather than the architectural decision itself. Keeping the ADR at the invariant level here would age better; the step-by-step assembly belongs in subsystem/runtime docs.

Based on learnings, "ADRs in prisma/prisma-next should document architectural design decisions and the key constraints/assumptions only. Do not include implementation algorithms, emitter derivation logic, or step-by-step derivation/migration rules."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/architecture` docs/adrs/ADR 208 - Higher-order codecs for parameterized
types.md around lines 166 - 175, The ADR currently includes implementation-level
algorithmic steps (the numbered "forColumn" build sequence, caching/validation
order and materialization details) that should be removed from the ADR and moved
to runtime/subsystem documentation; edit the ADR so it only documents the
high-level decision and invariants (that a descriptor map keyed by codecId
exists, that descriptorFor(codecId) exposes metadata, and forColumn(table,
column) resolves per-instance vs singleton codecs) and remove the detailed
prebuild steps referencing storage.tables[].columns[], descriptor.factory(...),
descriptor.paramsSchema['~standard'].validate(...), and decode(...) validation
behavior; instead add a short pointer/note in the ADR referencing the runtime
docs where the concrete assembly, caching, and JSON-schema validation
implementation is described.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/architecture` docs/adrs/ADR 208 - Higher-order codecs for parameterized
types.md:
- Around line 258-259: Replace the bullet that mentions "Mongo control-plane
parameterized-codecs slot" and any reference to "parameterizedCodecs:" with
phrasing that Mongo will adopt the unified "codecs:" registration surface (e.g.,
"Mongo control-plane to adopt unified codecs: registration surface") so the ADR
no longer reintroduces the retired `parameterized-codecs slot` vocabulary and
matches the deleted `parameterizedCodecs:` slot stated earlier.

In `@packages/1-framework/1-core/framework-components/README.md`:
- Line 34: The README incorrectly states that TypeScript bivariance permits
synchronous method bodies to satisfy Promise return types and shows an example
using property syntax and an optional ctx; fix the text and example: update the
explanation to state that bivariance only affects parameter type checking and
that methods declared to return Promise<T> must return a compatible Promise (use
async or explicitly return a Promise), change the sketch to extend CodecImpl and
implement encode(...) and decode(...) as class methods (not property shorthand),
and make the ctx parameter required and use ctx.signal (not ctx?.signal) in the
method signatures and bodies; reference the CodecImpl class and the
encode/decode methods when making these edits.

---

Outside diff comments:
In `@docs/architecture` docs/adrs/ADR 204 - Single-Path Async Codec Runtime.md:
- Around line 43-56: This section currently describes defineCodec()/mongoCodec()
and the Codec interface as if they are current; mark these sentences as
historical by adding a short qualifier (e.g., "Historical:", "Legacy behavior:",
or "Former design:") before the paragraph that explains that defineCodec() lifts
sync methods to Promise-returning query-time methods and the listed Codec shape
(encode/decode behavior), and update any present-tense verbs to past-tense for
symbols like defineCodec(), mongoCodec(), Codec, encode, decode, encodeJson,
decodeJson so it clearly reads as retired/legacy mechanics rather than current
behavior.

---

Nitpick comments:
In `@docs/architecture` docs/adrs/ADR 204 - Single-Path Async Codec Runtime.md:
- Line 237: The ADR includes low-level wiring and file-path detail; remove the
implementation mechanics and file paths and rephrase to the decision/constraint
level: state that component descriptors declare codecs
(ComponentMetadata.types.codecTypes.codecDescriptors), the framework aggregates
those via the execution-stack into a single MongoCodecRegistry exposed on the
execution context (context.codecs) by createMongoExecutionContext, and that
MongoRuntimeOptions no longer accepts a codecs field; move the detailed folding
algorithm and any package/file-specific implementation (e.g., the previous
package paths) into a linked subsystem implementation doc instead of the ADR
body.

In `@docs/architecture` docs/adrs/ADR 208 - Higher-order codecs for parameterized
types.md:
- Around line 166-175: The ADR currently includes implementation-level
algorithmic steps (the numbered "forColumn" build sequence, caching/validation
order and materialization details) that should be removed from the ADR and moved
to runtime/subsystem documentation; edit the ADR so it only documents the
high-level decision and invariants (that a descriptor map keyed by codecId
exists, that descriptorFor(codecId) exposes metadata, and forColumn(table,
column) resolves per-instance vs singleton codecs) and remove the detailed
prebuild steps referencing storage.tables[].columns[], descriptor.factory(...),
descriptor.paramsSchema['~standard'].validate(...), and decode(...) validation
behavior; instead add a short pointer/note in the ADR referencing the runtime
docs where the concrete assembly, caching, and JSON-schema validation
implementation is described.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yml

Review profile: CHILL

Plan: Pro

Run ID: 788f2e6c-0cb2-4466-aa83-d810249436a2

📥 Commits

Reviewing files that changed from the base of the PR and between 0e3aafc and c99c1ba.

📒 Files selected for processing (114)
  • docs/README.md
  • docs/Testing Guide.md
  • docs/architecture docs/adrs/ADR 152 - Execution Plane Descriptors and Instances.md
  • docs/architecture docs/adrs/ADR 184 - Codec-owned value serialization.md
  • docs/architecture docs/adrs/ADR 186 - Codec-dispatched type rendering.md
  • docs/architecture docs/adrs/ADR 202 - Codec trait system.md
  • docs/architecture docs/adrs/ADR 204 - Single-Path Async Codec Runtime.md
  • docs/architecture docs/adrs/ADR 205 - SQL cast emission is adapter policy.md
  • docs/architecture docs/adrs/ADR 207 - Codec call context per-query AbortSignal and column metadata.md
  • docs/architecture docs/adrs/ADR 208 - Higher-order codecs for parameterized types.md
  • docs/architecture docs/adrs/ADR 209 - Mongo result-shape as a structural plan field.md
  • docs/architecture docs/subsystems/2. Contract Emitter & Types.md
  • docs/reference/codec-authoring-guide.md
  • docs/reference/community-generator-migration-analysis.md
  • docs/reference/framework-gaps.md
  • docs/reference/typescript-patterns.md
  • examples/prisma-next-demo/test/no-emit-typed-flow.test-d.ts
  • packages/1-framework/0-foundation/contract/package.json
  • packages/1-framework/1-core/framework-components/README.md
  • packages/1-framework/1-core/framework-components/src/control/control-stack.ts
  • packages/1-framework/1-core/framework-components/src/exports/codec.ts
  • packages/1-framework/1-core/framework-components/src/shared/codec-descriptor.ts
  • packages/1-framework/1-core/framework-components/src/shared/codec-types.ts
  • packages/1-framework/1-core/framework-components/src/shared/codec.ts
  • packages/1-framework/1-core/framework-components/src/shared/column-spec.ts
  • packages/1-framework/1-core/framework-components/src/shared/framework-components.ts
  • packages/1-framework/1-core/framework-components/test/codec-call-context.types.test-d.ts
  • packages/1-framework/1-core/framework-components/test/codec-types.types.test-d.ts
  • packages/1-framework/1-core/framework-components/test/codec.test.ts
  • packages/1-framework/1-core/framework-components/test/codec.types.test-d.ts
  • packages/1-framework/1-core/framework-components/test/control-stack.test.ts
  • packages/1-framework/2-authoring/contract/README.md
  • packages/1-framework/2-authoring/contract/src/descriptors.ts
  • packages/1-framework/2-authoring/contract/src/index.ts
  • packages/1-framework/2-authoring/contract/test/descriptors.test.ts
  • packages/1-framework/2-authoring/ids/package.json
  • packages/1-framework/2-authoring/ids/src/index.ts
  • packages/1-framework/3-tooling/cli/src/control-api/contract-enrichment.ts
  • packages/1-framework/3-tooling/cli/test/config-types.test.ts
  • packages/1-framework/3-tooling/cli/test/control-api/contract-enrichment.test.ts
  • packages/1-framework/3-tooling/emitter/src/domain-type-generation.ts
  • packages/1-framework/3-tooling/emitter/test/domain-type-generation.test.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/README.md
  • packages/2-mongo-family/1-foundation/mongo-codec/src/codec-registry.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/src/codecs.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/src/exports/index.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs-ctx.test-d.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs-ctx.test.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs.test-d.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs.test.ts
  • packages/2-mongo-family/2-authoring/contract-psl/src/derive-json-schema.ts
  • packages/2-mongo-family/2-authoring/contract-psl/test/derive-json-schema.test.ts
  • packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.polymorphism.test.ts
  • packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.test.ts
  • packages/2-mongo-family/7-runtime/README.md
  • packages/2-mongo-family/7-runtime/src/mongo-execution-stack.ts
  • packages/2-mongo-family/7-runtime/test/codecs/decoding.test.ts
  • packages/2-mongo-family/7-runtime/test/decode.integration.test.ts
  • packages/2-mongo-family/7-runtime/test/mongo-execution-stack.test.ts
  • packages/2-mongo-family/7-runtime/test/mongo-middleware.test.ts
  • packages/2-mongo-family/7-runtime/test/mongo-runtime-abort.test.ts
  • packages/2-sql/2-authoring/contract-psl/src/provider.ts
  • packages/2-sql/2-authoring/contract-psl/src/psl-column-resolution.ts
  • packages/2-sql/2-authoring/contract-psl/test/fixtures.ts
  • packages/2-sql/2-authoring/contract-psl/test/provider.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/ts-psl-parity.test.ts
  • packages/2-sql/2-authoring/contract-ts/src/contract-definition.ts
  • packages/2-sql/2-authoring/contract-ts/src/contract-dsl.ts
  • packages/2-sql/2-authoring/contract-ts/src/contract-lowering.ts
  • packages/2-sql/2-authoring/contract-ts/test/config-types.test.ts
  • packages/2-sql/2-authoring/contract-ts/test/contract-builder.contract-definition.test.ts
  • packages/2-sql/2-authoring/contract-ts/test/contract-builder.value-objects.test.ts
  • packages/2-sql/2-authoring/contract-ts/test/helpers/column-descriptor.ts
  • packages/2-sql/3-tooling/emitter/test/emitter-hook.typeref-resolver.test.ts
  • packages/2-sql/4-lanes/relational-core/README.md
  • packages/2-sql/4-lanes/relational-core/package.json
  • packages/2-sql/4-lanes/relational-core/src/ast/adapter-types.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/codec-types.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/sql-codec-helpers.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/types.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/validate-param-refs.ts
  • packages/2-sql/4-lanes/relational-core/src/codec-descriptor-registry.ts
  • packages/2-sql/4-lanes/relational-core/src/exports/ast.ts
  • packages/2-sql/4-lanes/relational-core/src/exports/codec-descriptor-registry.ts
  • packages/2-sql/4-lanes/relational-core/src/expression.ts
  • packages/2-sql/4-lanes/relational-core/src/query-lane-context.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-factory-ctx.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-factory-ctx.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-factory.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-factory.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-types.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/refs-propagation.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codec-helpers.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codecs.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codecs.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/test-codec.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/test-helpers.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/validate-param-refs.test.ts
  • packages/2-sql/4-lanes/relational-core/test/expression.test.ts
  • packages/2-sql/4-lanes/relational-core/test/typed-codec-flow.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/utils.ts
  • packages/2-sql/4-lanes/relational-core/tsdown.config.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/builder-base.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/expression-impl.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/field-proxy.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/functions.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/mutation-impl.ts
  • packages/2-sql/4-lanes/sql-builder/test/runtime/field-proxy.test.ts
  • packages/2-sql/4-lanes/sql-builder/test/runtime/functions.test.ts
  • packages/2-sql/5-runtime/src/codecs/decoding.ts
  • packages/2-sql/5-runtime/src/codecs/encoding.ts
  • packages/2-sql/5-runtime/src/codecs/json-schema-validation.ts
  • packages/2-sql/5-runtime/src/codecs/validation.ts
💤 Files with no reviewable changes (7)
  • packages/1-framework/2-authoring/contract/src/descriptors.ts
  • packages/2-sql/5-runtime/src/codecs/json-schema-validation.ts
  • packages/2-mongo-family/7-runtime/test/decode.integration.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-types.test.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/adapter-types.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs-ctx.test.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs-ctx.test-d.ts
✅ Files skipped from review due to trivial changes (33)
  • packages/2-sql/4-lanes/relational-core/src/exports/codec-descriptor-registry.ts
  • packages/2-sql/4-lanes/relational-core/tsdown.config.ts
  • packages/1-framework/0-foundation/contract/package.json
  • docs/architecture docs/adrs/ADR 202 - Codec trait system.md
  • packages/2-sql/2-authoring/contract-ts/test/helpers/column-descriptor.ts
  • packages/1-framework/1-core/framework-components/test/codec-call-context.types.test-d.ts
  • packages/2-sql/2-authoring/contract-ts/test/config-types.test.ts
  • docs/architecture docs/subsystems/2. Contract Emitter & Types.md
  • docs/architecture docs/adrs/ADR 205 - SQL cast emission is adapter policy.md
  • packages/2-sql/2-authoring/contract-ts/src/contract-definition.ts
  • packages/2-mongo-family/7-runtime/src/mongo-execution-stack.ts
  • packages/1-framework/2-authoring/ids/package.json
  • packages/1-framework/2-authoring/ids/src/index.ts
  • packages/2-sql/3-tooling/emitter/test/emitter-hook.typeref-resolver.test.ts
  • docs/architecture docs/adrs/ADR 186 - Codec-dispatched type rendering.md
  • docs/README.md
  • packages/2-sql/2-authoring/contract-ts/src/contract-dsl.ts
  • docs/reference/community-generator-migration-analysis.md
  • docs/architecture docs/adrs/ADR 152 - Execution Plane Descriptors and Instances.md
  • packages/1-framework/2-authoring/contract/README.md
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-factory.test.ts
  • packages/2-sql/2-authoring/contract-ts/test/contract-builder.value-objects.test.ts
  • docs/architecture docs/adrs/ADR 209 - Mongo result-shape as a structural plan field.md
  • packages/2-mongo-family/7-runtime/README.md
  • docs/reference/framework-gaps.md
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/validate-param-refs.test.ts
  • packages/2-mongo-family/7-runtime/test/mongo-execution-stack.test.ts
  • docs/architecture docs/adrs/ADR 207 - Codec call context per-query AbortSignal and column metadata.md
  • docs/reference/codec-authoring-guide.md
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-factory-ctx.test.ts
  • packages/2-sql/4-lanes/relational-core/README.md
  • docs/Testing Guide.md
🚧 Files skipped from review as they are similar to previous changes (60)
  • packages/2-sql/4-lanes/relational-core/package.json
  • packages/1-framework/2-authoring/contract/src/index.ts
  • packages/2-mongo-family/7-runtime/test/mongo-runtime-abort.test.ts
  • packages/2-sql/2-authoring/contract-psl/test/ts-psl-parity.test.ts
  • packages/2-sql/2-authoring/contract-psl/src/provider.ts
  • packages/1-framework/3-tooling/cli/test/config-types.test.ts
  • packages/2-sql/4-lanes/relational-core/src/exports/ast.ts
  • packages/2-sql/2-authoring/contract-ts/src/contract-lowering.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/builder-base.ts
  • packages/2-sql/5-runtime/src/codecs/validation.ts
  • packages/1-framework/3-tooling/emitter/src/domain-type-generation.ts
  • packages/2-mongo-family/2-authoring/contract-psl/test/derive-json-schema.test.ts
  • packages/2-sql/4-lanes/relational-core/src/expression.ts
  • packages/1-framework/2-authoring/contract/test/descriptors.test.ts
  • packages/1-framework/1-core/framework-components/src/shared/framework-components.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/mutation-impl.ts
  • packages/1-framework/1-core/framework-components/src/shared/codec.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/refs-propagation.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-factory.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/validate-param-refs.ts
  • packages/1-framework/1-core/framework-components/test/codec-types.types.test-d.ts
  • packages/1-framework/3-tooling/cli/test/control-api/contract-enrichment.test.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/expression-impl.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/codec-factory-ctx.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/src/codec-descriptor-registry.ts
  • packages/2-sql/4-lanes/relational-core/test/typed-codec-flow.test-d.ts
  • packages/2-sql/2-authoring/contract-ts/test/contract-builder.contract-definition.test.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/sql-codecs.ts
  • packages/2-sql/4-lanes/relational-core/test/expression.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codecs.test.ts
  • packages/1-framework/1-core/framework-components/src/shared/column-spec.ts
  • packages/2-sql/2-authoring/contract-psl/test/fixtures.ts
  • packages/2-sql/5-runtime/src/codecs/encoding.ts
  • packages/1-framework/3-tooling/cli/src/control-api/contract-enrichment.ts
  • packages/2-sql/4-lanes/sql-builder/test/runtime/functions.test.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codecs.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/test/ast/sql-codec-helpers.test.ts
  • packages/1-framework/1-core/framework-components/test/codec.types.test-d.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/types.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/README.md
  • packages/2-sql/4-lanes/relational-core/src/ast/sql-codec-helpers.ts
  • packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.test.ts
  • examples/prisma-next-demo/test/no-emit-typed-flow.test-d.ts
  • packages/2-mongo-family/7-runtime/test/codecs/decoding.test.ts
  • packages/1-framework/3-tooling/emitter/test/domain-type-generation.test.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/src/codec-registry.ts
  • packages/1-framework/1-core/framework-components/src/control/control-stack.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/test/codecs.test-d.ts
  • packages/2-sql/5-runtime/src/codecs/decoding.ts
  • packages/2-sql/2-authoring/contract-psl/test/provider.test.ts
  • packages/2-mongo-family/7-runtime/test/mongo-middleware.test.ts
  • packages/2-mongo-family/2-authoring/contract-psl/test/interpreter.polymorphism.test.ts
  • packages/1-framework/1-core/framework-components/test/control-stack.test.ts
  • packages/2-sql/4-lanes/relational-core/test/utils.ts
  • packages/2-mongo-family/1-foundation/mongo-codec/src/codecs.ts
  • packages/2-sql/4-lanes/sql-builder/src/runtime/field-proxy.ts
  • packages/1-framework/1-core/framework-components/src/exports/codec.ts
  • packages/1-framework/1-core/framework-components/src/shared/codec-descriptor.ts
  • packages/2-sql/4-lanes/relational-core/src/query-lane-context.ts
  • packages/2-sql/4-lanes/relational-core/src/ast/codec-types.ts

Comment on lines +258 to +259
- **Mongo control-plane parameterized-codecs slot.** Aligns Mongo with the SQL family's slot shape — separate ticket.
- **Future schema libraries.** zod, valibot, etc. ship as parallel per-library extensions when each library has a clean serialize / rehydrate story. The arktype-json package is the structural template.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Rename this future-work item away from parameterized-codecs slot.

Lines 248-249 already say the parallel parameterizedCodecs: slot is deleted, so this bullet reintroduces retired vocabulary and makes the ADR self-contradictory. Rephrase it in terms of Mongo adopting the unified codecs: registration surface instead.

As per coding guidelines, "Update design docs to reflect the current state only, not the transition history or legacy approaches."

🧰 Tools
🪛 LanguageTool

[style] ~258-~258: Three successive sentences begin with the same word. Consider rewording the sentence or use a thesaurus to find a synonym.
Context: ... so the gap is authoring-time only. - **Mongo control-plane parameterized-codecs slot...

(ENGLISH_WORD_REPEAT_BEGINNING_RULE)


[grammar] ~259-~259: Ensure spelling is correct
Context: ... clean serialize / rehydrate story. The arktype-json package is the structural template...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/architecture` docs/adrs/ADR 208 - Higher-order codecs for parameterized
types.md around lines 258 - 259, Replace the bullet that mentions "Mongo
control-plane parameterized-codecs slot" and any reference to
"parameterizedCodecs:" with phrasing that Mongo will adopt the unified "codecs:"
registration surface (e.g., "Mongo control-plane to adopt unified codecs:
registration surface") so the ADR no longer reintroduces the retired
`parameterized-codecs slot` vocabulary and matches the deleted
`parameterizedCodecs:` slot stated earlier.

The base `Codec` interface lands on the seam between **query-time** methods (per-row, IO-relevant) and **build-time** methods (per-contract-load):

- Query-time: `encode(value): Promise<TWire>` and `decode(wire): Promise<TInput>` are required and **Promise-returning at the public boundary**, regardless of whether the codec body is synchronous or asynchronous. Family factories (`codec()` for SQL, `mongoCodec()` for Mongo) accept either sync or async author functions and lift sync ones to Promise-shaped methods, so authors write whichever shape is natural per method without annotations.
- Query-time: `encode(value): Promise<TWire>` and `decode(wire): Promise<TInput>` are required and **Promise-returning at the public boundary**, regardless of whether the codec body is synchronous or asynchronous. Codec authors extend `CodecImpl` (per [ADR 208 — Higher-order codecs for parameterized types](../../../../../docs/architecture%20docs/adrs/ADR%20208%20-%20Higher-order%20codecs%20for%20parameterized%20types.md)) and write whichever shape is natural per method — TypeScript bivariance accepts sync method bodies satisfying the `Promise<…>` return type, and the runtime always awaits the result.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

In TypeScript, can a class method returning Toverride or implement a method declared as returningPromise? Does parameter bivariance affect return-type compatibility, and what is the correct class syntax for an async method?

💡 Result:

Yes: a method declared to return T cannot override/implement a method declared to return Promise in TypeScript; the return types are not compatible. 1) Return-type compatibility (T vs Promise<T]) - If the base method’s signature says it returns Promise, the overriding/implementing method must also return a Promise (specifically, the built-in Promise return for an async implementation). TypeScript doesn’t allow an async method to claim it returns anything other than the global Promise type; otherwise you get an error like “The return type of an async function or method must be the global Promise type.” [1] - In general, Promise is an output type wrapper; you can’t replace it with a bare T without breaking substitutability. - A related generics override example shows the compiler rejecting an override where the base method allows T | Promise but the derived method narrows it to just T (error: the override return type isn’t assignable to the base return type). [2] 2) Does parameter bivariance affect return-type compatibility? - No. Parameter bivariance/bivariance affects assignability based on function parameter positions, not return-type positions. TypeScript’s variance rules for functions are about where the type parameter appears: return positions are treated differently from parameter positions. [3][4] - In particular, strictFunctionTypes changes function type parameter checking to be contravariant (for function types), but it explicitly excludes methods from that stricter variance computation to “continue to mostly relate covariantly” (i.e., method parameter bivariance behavior remains). [3][4] - Even if parameters are bivariant, return types must still be compatible; covariance/bivariance of parameters does not make Promise assignable to T. 3) Correct class syntax for an async method - In a class, you mark the method with async and (optionally) annotate its Promise return type: - async myMethod(args:...): Promise {... } - Example syntax: - class C { async getValue: Promise { return 1; } } If you need an inheritance-friendly “return the current subtype” pattern, use polymorphic this / this-return typing (different concern from Promise vs non-Promise): a method can be declared to return this so subclasses keep the correct instance type. [5] Practical guidance: keep the return type wrapper the same across base/derived/interface—i.e., Promise stays Promise. If you have an implementation that sometimes returns synchronously, type the method as T | Promise at the interface boundary instead of overriding to bare T. [2]

Citations:


🏁 Script executed:

# Find and read the README file mentioned in the review comment
find . -path "*/packages/1-framework/1-core/framework-components/README.md" -type f | head -1

Repository: prisma/prisma-next

Length of output: 123


🏁 Script executed:

# Read the README file, focusing on lines around 34 and 61-63
if [ -f "packages/1-framework/1-core/framework-components/README.md" ]; then
  echo "=== Lines 30-40 ===" && sed -n '30,40p' packages/1-framework/1-core/framework-components/README.md | cat -n
  echo ""
  echo "=== Lines 55-70 ===" && sed -n '55,70p' packages/1-framework/1-core/framework-components/README.md | cat -n
else
  echo "File not found at expected path"
  # Search for the file
  find . -name "README.md" -path "*/framework-components/*" 2>/dev/null
fi

Repository: prisma/prisma-next

Length of output: 2985


🏁 Script executed:

# Find the CodecImpl class definition
rg "class CodecImpl|interface CodecImpl|type CodecImpl" --type ts --type tsx -A 10

Repository: prisma/prisma-next

Length of output: 90


🏁 Script executed:

# Find CodecCallContext definition
rg "interface CodecCallContext|type CodecCallContext" --type ts --type tsx -A 5

Repository: prisma/prisma-next

Length of output: 90


🏁 Script executed:

# Also search for how codec authors are expected to implement these methods
rg "encode.*Promise.*value" packages/1-framework/1-core/framework-components/ --type ts --type tsx -B 2 -A 5

Repository: prisma/prisma-next

Length of output: 90


🏁 Script executed:

# Find the CodecImpl class definition
rg "class CodecImpl|interface CodecImpl|type CodecImpl" -A 10

Repository: prisma/prisma-next

Length of output: 5503


🏁 Script executed:

# Find CodecCallContext definition
rg "interface CodecCallContext|type CodecCallContext" -A 5

Repository: prisma/prisma-next

Length of output: 7395


🏁 Script executed:

# Search within the framework-components directory
cd packages/1-framework/1-core/framework-components && find . -name "*.ts" -o -name "*.tsx" | head -20

Repository: prisma/prisma-next

Length of output: 789


🏁 Script executed:

cat -n packages/1-framework/1-core/framework-components/src/shared/codec.ts | head -80

Repository: prisma/prisma-next

Length of output: 4575


🏁 Script executed:

# Look for the encode and decode method signatures
rg "encode|decode" packages/1-framework/1-core/framework-components/src/shared/codec.ts -B 2 -A 3 | head -60

Repository: prisma/prisma-next

Length of output: 3341


Fix the Promise-returning codec example and bivariance explanation.

Line 34 incorrectly claims TypeScript bivariance allows sync method bodies to satisfy Promise<…> return types. Bivariance affects only parameter checking, not return-type compatibility; a method overriding Promise<T> must return a compatible Promise type. Additionally, the sketch on lines 61–63 uses property syntax (encode: async ...) instead of class method syntax, which contradicts the description that codec authors extend CodecImpl. The ctx?.signal pattern also incorrectly implies the ctx parameter is optional when it is required.

📝 Suggested fix
- Query-time: `encode(value): Promise<TWire>` and `decode(wire): Promise<TInput>` are required and **Promise-returning at the public boundary**, regardless of whether the codec body is synchronous or asynchronous. Codec authors extend `CodecImpl` (per [ADR 208 — Higher-order codecs for parameterized types](../../../../../docs/architecture%20docs/adrs/ADR%20208%20-%20Higher-order%20codecs%20for%20parameterized%20types.md)) and write whichever shape is natural per method — TypeScript bivariance accepts sync method bodies satisfying the `Promise<…>` return type, and the runtime always awaits the result.
+ Query-time: `encode(value): Promise<TWire>` and `decode(wire): Promise<TInput>` are required and **Promise-returning at the public boundary**. Codec authors extend `CodecImpl` (per [ADR 208 — Higher-order codecs for parameterized types](../../../../../docs/architecture%20docs/adrs/ADR%20208%20-%20Higher-order%20codecs%20for%20parameterized%20types.md)); if the body is logically synchronous, the method still needs to return a `Promise`-compatible value (for example by marking it `async`). The runtime always awaits the result.
...
- // Sketch — codec authors extend `CodecImpl`; class methods receive `(value, ctx)`.
- encode: async (v: string, ctx) =>
-   kms.encrypt({ plaintext: v }, { signal: ctx?.signal });
+ // Sketch — codec authors extend `CodecImpl`; class methods receive `(value, ctx)`.
+ async encode(v: string, ctx: CodecCallContext) {
+   return kms.encrypt({ plaintext: v }, { signal: ctx.signal });
+ }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/1-framework/1-core/framework-components/README.md` at line 34, The
README incorrectly states that TypeScript bivariance permits synchronous method
bodies to satisfy Promise return types and shows an example using property
syntax and an optional ctx; fix the text and example: update the explanation to
state that bivariance only affects parameter type checking and that methods
declared to return Promise<T> must return a compatible Promise (use async or
explicitly return a Promise), change the sketch to extend CodecImpl and
implement encode(...) and decode(...) as class methods (not property shorthand),
and make the ctx parameter required and use ctx.signal (not ctx?.signal) in the
method signatures and bodies; reference the CodecImpl class and the
encode/decode methods when making these edits.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants